Leetcode 213-220刷题笔记(非困难题目)

本文探讨了如何解决环形数组的打家劫舍问题,利用拆分和动态规划策略,并介绍了快速找到数组中第K大元素的方法,包括快排和堆排序。此外,还有回溯算法的应用,如组合总和3和判断重复元素,以及优化的查找重复元素解决方案。
摘要由CSDN通过智能技术生成

213.打家劫舍2

该题目和之前的打家劫舍有点类似,不过该题目是一个的家庭是环形(代表第一位和最后一位不能够同时盗窃)。

讲这道题我们可以将环形进行拆分,既然首位不发同时获取到,那么我们不如将这个环拆分成两个单列表(一个不包含第一家,一个不包含最后一家),根据这个情况的话我们可以将两个单列进行两次打家劫舍,取最大值即可。

注意:有两种特殊情况需要进行考虑一下,长度 = 0 / = 1,因为无法数组无法进行割舍。

   public int rob(int[] nums) {
        if(nums.length == 0) {
            return 0;
        }
        if(nums.length == 1) {
            return nums[0];
        }
        int num1 = myRob(Arrays.copyOfRange(nums,0,nums.length - 1));
        int num2 = myRob(Arrays.copyOfRange(nums,1,nums.length));
        return Math.max(num1,num2);
    }
    public int myRob(int[] nums) {
        int[] dp = new int[nums.length + 1];
        int ans = nums[0];

        //从1开始偷
        dp[1] = nums[0];
        for(int i=2; i<dp.length; i++) {
            dp[i] = Math.max(dp[i - 1],dp[i - 2] + nums[i - 1]);
            ans = Math.max(ans,dp[i]);
        }

        return ans;
    }

215.数组中的第K个最大元素(Top K问题)

我们可以使用快排的分区思想,排序后左右都是局部有序,[小/大 < 基准值 < 大/小] 这样的结构。

所以我们可以轻易的判断出基准值所处在的位置(即前面有多少个大于自身的数,根据这个数目选择指针移动的方向)

    //寻找第K大数(代表前面有k个数)
    public int findKthLargest(int[] nums, int k) {
        return partition(nums,0,nums.length - 1,k);
    }

    //使用快排的思想(从大到小排序奥)
    public int partition(int[] nums, int left, int right, int k) {
        if(left > right) {
            return -1;
        }

        int l = left;
        int r = right;
        int target = nums[left];

        while(l < r) {
            while(l < r && nums[r] <= target) r--;
            while(l < r && nums[l] >= target) l++;

            if(l < r) {
                int temp = nums[l];
                nums[l] = nums[r];
                nums[r] = temp;
            }
        }
        //将比较值放在合适位置
        int temp = nums[l];
        nums[l] = nums[left];
        nums[left] = temp;

        //比target大的有多少个
        int before = l - left;
        if(before == k - 1) {
            return nums[l];
        }else if(before > k - 1) { //第K大还在更前面
            return partition(nums,left,l - 1,k);
        }else {
            return partition(nums,l + 1,right,k - before - 1);
        }
    }

还有一种堆排序的方法,创建一个小顶堆(堆顶为堆内最小值),该堆维护一个size = k,则整个数组遍历结束后堆顶即为topK。

    //寻找第K大数(代表前面有k个数)
    public int findKthLargest(int[] nums, int k) {
        //最小堆
        Queue<Integer> queue = new PriorityQueue<>();

        for(int i=0; i<nums.length; i++) {
            if(queue.size() < k) {
                queue.offer(nums[i]);
            }else {
                //此时堆顶为堆内最小值
                if(queue.peek() < nums[i]) {
                    queue.remove();
                    queue.offer(nums[i]);
                }
            }
        }

        return queue.remove();
    }

216.组合总和3

也是回溯算法,直接上代码了,没有什么难度。

    public List<List<Integer>> combinationSum3(int k, int n) {
        List<List<Integer>> lists = new ArrayList<>();
        dfs(lists,new ArrayList<>(),k,n,1);
        return lists;
    }

    public void dfs(List<List<Integer>> lists, List<Integer> list, int k, int n, int num) {
        if(k == 0 && n == 0) {
            lists.add(new ArrayList<>(list));
            return;
        }
        if(k <= 0) {
            return;
        }
        
        for(int i=num; i<=9; i++) {
            if(i > n) {
                break;
            }
            list.add(i);
            dfs(lists,list,k - 1,n - i, i + 1);
            list.remove(list.size() - 1);
        }
    }

217.存在重复元素

先排序直接在判断和前一位的关系即可。

    //判断是否存在重复元素
    public boolean containsDuplicate(int[] nums) {
        Arrays.sort(nums);
        
        for(int i=1; i<nums.length; i++) {
            if(nums[i - 1] == nums[i]) {
                return true;
            }
        }
        
        return false;
    }

219.存在重复元素2

该题目的要求就是在两个值相同的前提下,使得两个下标差的绝对值 <= k。

我们可以通过记录一个数对应的下标,如果出现重复时,则此时我们拥有当前下标和上一次出现该元素的下标,判断一下是否符合。

如果不符合要求的话,则更新map中保存的元素对应的下标,用于下次一重复进行判断。

    public boolean containsNearbyDuplicate(int[] nums, int k) {
        Map<Integer,Integer> map = new HashMap<>();
        
        for(int i=0; i<nums.length; i++) {
            if(map.containsKey(nums[i])) {
                int index = map.get(nums[i]);
                
                if(i - index <= k) {
                    return true;
                }
                
                map.put(nums[i],i);
            }else {
                map.put(nums[i],i);
            }
        }
        
        return false;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值