首页 > 其他分享 >2023-05-17 刷题

2023-05-17 刷题

时间:2023-05-17 21:57:39浏览次数:42  
标签:pre 遍历 return 17 05 int omitIdx ++ 刷题

算法题目1:【Mid】47. 全排列 II

思路分析

  1. 将原问题转换成子问题,先不考虑重复元素,例如 P{1,2,3} = {"1" + P{2,3}, "2" + P{1,3}, "3" + P{1,2}}。之后再考虑重复元素。
  2. 怎么枚举?枚举每个位置可以填哪些数。【这种枚举方式能保证字典序,除此外,还有一种,枚举每个数可以放到哪个位置上,这题不适合】
  3. 怎么去重?首先对输入的数组进行排序,目的是在当前位置枚举可以使用哪些元素时,可以将相同的元素规定一个顺序。对于1 1 1 2 2 这种,重复的数,规定只能从前往后使用。visit[]数组标记每个数是否使用了。对于三个1,要使用第二个1,只有当visit[0] = true。同理,要使用第三个1,只能当visit[1] = true。 这样就能保证相同元素在所有的全排列结果中的相对顺序是唯一的。

复杂度分析

  • 时间:O(nlogn + n! * n). 对输入数组进行排序,O(nlogn), dfs递归调用,实际是枚举每个位置,反应在参数pos (也等于path.size(), 这里没有省略pos,是因为显示写出pos更易懂一点) 。因此,总共有n个位置,每个位置遍历n个元素,依次将没有使用过的元素,放在该位置上,然后进行递归调用,最后枚举到的结果,需要copy一遍到结果数组中,所以这步的时间复杂度就是:O(n! * n).
  • 空间:O(n). 如果不考虑结果数组的话,中间用到的visited数组以及递归的栈最大深度n, 因此空间是O(n).

本题难点:去重。

class Solution {
    public List<List<Integer>> permuteUnique(int[] A) { // time: O(nlogn + n!*n), space: O(n)
        ans = new ArrayList<>();
        visited = new boolean[A.length];

        Arrays.sort(A);
        dfs(A, 0, new ArrayList<>());

        return ans;
    }

    List<List<Integer>> ans;
    boolean[] visited;

    void dfs(int[] A, int pos, List<Integer> path) {
        if (pos == A.length) {
            ans.add(new ArrayList<>(path));
            return;
        }
        // 枚举当前pos位置,能填哪些数
        for(int i = 0; i < A.length; i++) {
            if (visited[i] || 
                i > 0 && A[i] == A[i-1] && !visited[i - 1]
            ) {
                continue;
            }
            // 否则说明A[i]这个数可以使用
            visited[i] = true;
            path.add(A[i]);

            dfs(A, pos + 1, path);

            path.remove(path.size() - 1);
            visited[i] = false;
        }
    }
}

【easy】1909. 删除一个元素使数组严格递增

思路:遍历找到第一个逆序对,然后尝试删除其中一个,看剩下来是否严格递增。思路很简单,代码实现刚开始可能有点绕,后来想清楚了就简单了。

  public boolean canBeIncreasing(int[] A) { // time: O(n), space: O(1)
        int n = A.length;
        for(int i = 1; i < n; i++) {
            if (A[i-1] >= A[i]) { // 找到一个逆序对
                return isIncreasing(A, i - 1) // try to delete A[i-1]
                    || isIncreasing(A, i);    // try to delete A[i]
            }
        }
        return true;
    }

    boolean isIncreasing(int[] A, int omitIdx) {
        int pre = -1;
        for(int i = 0; i < A.length; i++) { // 因为omitIdx有可能是0,所以这里要从0开始遍历,不能假定A[0]始终都存在
            if (i == omitIdx) {
                continue;
            }
            if (pre > -1 && A[pre] >= A[i]) {
                return false;
            }
            pre = i;
        }
        return true;
    }

复杂度分析:

  • 时间:O(n),找到第一个逆序对遍历一遍,然后判断删除元素之后,是否递增,最多遍历两遍。所以时间复杂度是O(n)
  • 空间:O(1)

细节上可以做一些优化,isIncreasing函数没必要从头开始,从omitIdx的下一个开始也可以。

  boolean isIncreasing(int[] A, int omitIdx) { // 优化之后,最多遍历两遍
        int pre = omitIdx - 1;
        for(int i = omitIdx + 1; i < A.length; i++) {            
            if (pre > -1 && A[pre] >= A[i]) {
                return false;
            }
            pre = i;
        }
        return true;
    }

还可以再优化一下,只遍历一遍,代码如下

  public boolean canBeIncreasing(int[] A) { // time: O(n), space: O(1)
        int n = A.length;
        int count = 0;
        for(int i = 1; i < n; i++) {
            if (A[i-1] >= A[i]) {
                count++;
                if (i > 1 && A[i-2] >= A[i]) { // can't delete A[i-1]
                    // so try to delete A[i]
                    A[i] = A[i-1];
                } // else delete A[i-1], 优先删除A[i-1]因为它比A[i]大,删除它之后,递增的概率大一点?
            }
        }
        return count <= 1;
    }

算法题目2:【easy】1909. 删除一个元素使数组严格递增

思路:遍历找到第一个逆序对,然后尝试删除其中一个,看剩下来是否严格递增。思路很简单,代码实现刚开始可能有点绕,后来想清楚了就简单了。

   public boolean canBeIncreasing(int[] A) { // time: O(n), space: O(1)
        int n = A.length;
        for(int i = 1; i < n; i++) {
            if (A[i-1] >= A[i]) { // 找到一个逆序对
                return isIncreasing(A, i - 1) // try to delete A[i-1]
                    || isIncreasing(A, i);    // try to delete A[i]
            }
        }
        return true;
    }

    boolean isIncreasing(int[] A, int omitIdx) {
        int pre = -1;
        for(int i = 0; i < A.length; i++) { // 因为omitIdx有可能是0,所以这里要从0开始遍历,不能假定A[0]始终都存在
            if (i == omitIdx) {
                continue;
            }
            if (pre > -1 && A[pre] >= A[i]) {
                return false;
            }
            pre = i;
        }
        return true;
    }

复杂度分析:

  • 时间:O(n),找到第一个逆序对遍历一遍,然后判断删除元素之后,是否递增,最多遍历两遍。所以时间复杂度是O(n)
  • 空间:O(1)

细节上可以做一些优化,isIncreasing函数没必要从头开始,从omitIdx的下一个开始也可以。

    boolean isIncreasing(int[] A, int omitIdx) { // 优化之后,最多遍历两遍
        int pre = omitIdx - 1;
        for(int i = omitIdx + 1; i < A.length; i++) {            
            if (pre > -1 && A[pre] >= A[i]) {
                return false;
            }
            pre = i;
        }
        return true;
    }

还可以再优化一下,只遍历一遍,代码如下

  public boolean canBeIncreasing(int[] A) { // time: O(n), space: O(1)
        int n = A.length;
        int count = 0;
        for(int i = 1; i < n; i++) {
            if (A[i-1] >= A[i]) {
                count++;
                if (i > 1 && A[i-2] >= A[i]) { // can't delete A[i-1]
                    // so try to delete A[i]
                    A[i] = A[i-1];
                } // else delete A[i-1], 优先删除A[i-1]因为它比A[i]大,删除它之后,递增的概率大一点?
            }
        }
        return count <= 1;
    }

标签:pre,遍历,return,17,05,int,omitIdx,++,刷题
From: https://www.cnblogs.com/xianzhon/p/17410434.html

相关文章

  • 考研学习 | 每日回顾(2023年5月17日)
    昨天的考研数学笔记求解偏导数的时候一定要清楚当前谁是自变量:文内有小技巧求偏导时,函数的第一部分变量用1表示,第二部分变量用2表示......
  • Solon v2.2.17 发布,Java 新的生态型应用开发框架
    相对于SpringBoot和SpringCloud的项目:启动快5~10倍。(更快)qps高2~3倍。(更高)运行时内存节省1/3~1/2。(更少)打包可以缩小到1/2~1/10;比如,300Mb的变成了23Mb。(更小)同时支持jdk8,jdk11,jdk17,jdk20,graalvmnative(不会)因为依赖变多而启动很慢(以小诺......
  • 17、什么是反射?
    所谓反射,是java在运行时进行自我观察的能力,通过class、constructor、field、method四个方法获取一个类的各个组成部分。在Java运行时环境中,对任意一个类,可以知道类有哪些属性和方法。这种动态获取类的信息以及动态调用对象的方法的功能来自于反射机制。......
  • 每日总结 5.17
    今日进行了python的学习。对于昨天的测试代码进行了分析学习。R7-1字典合并d1=eval(input())d2=eval(input())forkeyind2.keys():d1[key]=d1.get(key,0)+d2[key]t=list(d1.items())t.sort(key=lambdax:ord(x[0])iftype(x[0])==strelsex[0])......
  • Python基础05
    成员运算符查看某个个体是否在群体中关键字:in在 notin不在name=['kevin','jack','tank']print('kevin'inname)print('lili'notinname)身份运算符比较是否相等关键字:==比较的是值是否相等  is比较内存代码是否相等s1=['kevin','tank'......
  • 2023/5/17
    L1-009N个数求和分数 20全屏浏览题目作者 陈越单位 浙江大学本题的要求很简单,就是求N个数字的和。麻烦的是,这些数字是以有理数分子/分母的形式给出的,你输出的和也必须是有理数的形式。输入格式:输入第一行给出一个正整数N(≤100)。随后一行按格式a1/b......
  • 5.17
    今天写了下web的登陆界面<%@pagelanguage="java"import="javax.sql.*"pageEncoding="utf-8"%><%@pageerrorPage="error.jsp"%><html><head><title>图书管理系统</title><linkrel="stylesheet&qu......
  • day73(2023.5.17)
    1.资源访问路径 2.获取请求头信息 运行结果: 运行结果: 3.获取请求头案例 运行结果: 4.HttpServletRequest对象的生命周期 5.HttpServletResponse对象 6.设置响应类型设置字符类型响应: 运行结果: 运行结果: 略。设置......
  • Linux多进程05-exec函数族
    execl:执行文件函数#include<unistd.h>intexecl(constchar*pathname,constchar*arg,...); 执行参数path字符串所代表的文件路径参数:-path:需要指定的执行的文件的路径或者名称(推荐使用绝对路径)-arg:是执行可......
  • STM32F051 MK电调 BLDC 直流无刷电机控制 基于STM32F051 cortex-M0
    STM32F051MK电调BLDC直流无刷电机控制基于STM32F051cortex-M0的电调开发板,包含原理图PCB工程文件,程序源码,BLDC控制入门资料,供初学者入门学习了解。ID:48299619798638569......