【Leecode笔记之Java|数组专题】第七周(10.19-10.25)

【DAY 22——数组专题】

第五题:数组中出现次数超过一半的数字在这里插入图片描述

分析:遇到相同的数则+1,遇到不同的数则-1.

class Solution {
    public int majorityElement(int[] nums) {
        int len = nums.length;
        int count = 0;
        int major = nums[0];
        int total = 0;
        for(int i = 0;i < len;i++){
            if(count == 0){
                major = nums[i];
            }
            if(nums[i] == major){
                count++;
            }
            else{
                count--;
            }
            
        }
        if(count > 0){
            for(int j = 0;j < len;j++){
                if(major == nums[j]){
                    total++;
                }
            }
            if(total > len/2){
                return major;
            }
            else{
                return 0;
            }
        }
        return 0;
    }
}

第六题:调整数组顺序,使奇数位于偶数前面

在这里插入图片描述分析:设置两个哨兵i,j。
I从头开始,假设所指的数为奇数,则往前,为偶数则不动;
j从最后开始,假设所指的数为偶数,则往前,为奇数,则不动;
当两个指针都不动的时候(i指向偶数,j指向奇数),交换位置,直到i>j

//执行用时:2 ms, 在所有 Java 提交中击败了99.72% 的用户
//内存消耗:46 MB, 在所有 Java 提交中击败了99.53% 的用户
class Solution {
    public int[] exchange(int[] nums) {
        int i = 0,j = nums.length-1;
        int temp;
        while(i < j){
            if((nums[i] % 2 == 0)&&(nums[j] % 2 != 0)){
                temp = nums[i];
                nums[i] = nums[j];
                nums[j] = temp;
                i++;
                j--;
            }
            if(nums[i] % 2 != 0){
                i++;
            }
            if(nums[j] % 2 == 0 ){
                j--;
            }
        }
        return nums;
    }
}

第七题:旋转数组的最小数字

在这里插入图片描述分析:这样的话,旋转数组最大值的后面一位就是最小值?
错,因为可能存在多个最大值,要找到最后一个
(但是不知道为什么,他给出的测试用例直接就是一个递增序列)
在这里插入图片描述 以最小值的点为分界,与最后一个数组元素比较,比他小的肯定排在最小值的右边,同理,比他大的排在最小值的左边,而且,最小值的左右边都是一个递增数列。
因此,利用这个特性,假如当前的这个数组元素比最后一个数大,则只需要查找该数的右半部分,否则,只需要查找该数的左半部分。这样的话,搜查的范围不断缩小一半,最终找到最小值所在的位置。

【DAY 23——数组专题】

第八题:连续子数组的最大和*(动态规划)*

在这里插入图片描述
分析:从这一题开始学习动态规划!首先看到题目第一反应是滑动窗口,但是想来就很复杂,因为这个子数组并没有限制长度。假如,以nums[i]为子数组的结束值,假如前边的数为正,则可加上,为负,则不加。

动态规划思想的精髓就是:1.要让第(n)步达到最值,那么第(n-1)步也要达到最值;2.且第(n)步受第(n-1)步影响;3.大问题都是由若干相同解法的子问题组成,只要满足这个条件的题,就可以用动态规划。

下一步就是构建模型:
1.状态,即子问题;
dp[i]代表以元素num[i]结尾的连续子数组最大和;
2.转移策略,自带剪枝;
假如dp[n-1] <= 0,则若加上,带来的只是负影响,因此还不如只要nums[i]
3.状态转移方程,根据前两步抽象而来;
假如dp[n-1] <= 0:执行dp[i] = nums[i];
否则,执行dp[i] = dp[i-1] + nums[i];
4.设计dp数组,保存子问题的解,避免重复计算。(像这一题就是将子数组解的值对应到dp数组相应的下标上,比较整个数组元素的值即可)
5.代码实现

//执行用时:1 ms, 在所有 Java 提交中击败了99.37% 的用户
//内存消耗:44.5 MB, 在所有 Java 提交中击败了99.72% 的用户
class Solution {
    public int maxSubArray(int[] nums) {
        int len = nums.length;
        int[] dp = new int[len];
        dp[0] = nums[0];
        for(int i = 1;i < len;i++){
            if(dp[i-1] > 0){
                dp[i] = dp[i-1] + nums[i];
            }
            else{
                dp[i] = nums[i];
            }
        }
        int max = dp[0];
        for(int j = 0;j < len;j++){
            if(dp[j] > max){
                max = dp[j];
            }
        }
        return max;
    }
}
//这个是上边的内存优化版本,将上边的数组用两个变量former和cur来表示
//这里的cur有两个作用,一是指向当前的nums[i],二是保存当前子问题的值(和max比较,假如比max大,则更新max)
//执行用时:1 ms, 在所有 Java 提交中击败了99.37% 的用户
//内存消耗:44.6 MB, 在所有 Java 提交中击败了99.44% 的用户
class Solution {
    public int maxSubArray(int[] nums) {
        int max = nums[0];
        int former = 0;//用于记录dp[i-1]的值,对于dp[0]而言,其前面的dp[-1]=0
        int cur = nums[0];//用于记录dp[i]的值
        for(int num:nums){
            cur = num;
            if(former>0) cur +=former;
            if(cur>max) max = cur;
            former=cur;//更新former
        }
        return max;
    }
}

第九题:早餐组合

在这里插入图片描述
分析:第一反应肯定是直接两层for…,或者一层for另一个数组遍历。
更优的解法是,将两个数组从小到大排序,设定两个哨兵,每个数组各一个,哨兵A从staple的头部出发,哨兵B从drinks的尾部出发,一大一小这样容易凑到(从中间开始凑用二分法也可),并且省时(因为凑到了x元,那么比尾部的大数小的数都满足条件,就不必遍历)。

//执行用时:86 ms, 在所有 Java 提交中击败了54.91% 的用户
//内存消耗:57.8 MB, 在所有 Java 提交中击败了86.82% 的用户
class Solution {
    public int breakfastNumber(int[] staple, int[] drinks, int x) {
        Arrays.sort(staple);
        Arrays.sort(drinks);
        int i = 0;
        int j = drinks.length-1;
        int ans = 0;
        while(i <= staple.length-1 && j >= 0){
            if(staple[i] + drinks[j] > x){
                j--;
            }
            else{
                ans += j+1;
                ans %= 1000000007;//
                i++;
            }
        }
        return ans;
    }
}

第十题:0~n-1中缺失的数字

在这里插入图片描述分析:
第一种思路:还是之前那个以空间换时间的方法;
第二种思路:第一个nums[i]不等于i的数就是缺失的数(假如说所有数都在和他下标相同的位置,那么缺少的就是最后那个数,也就是nums.lenth+1);思路二的实现有两种方法:二分查找、双指针
第三种思路:直接顺序遍历,碰到第一个nums[i]!=i的输出,然后再加上两个情况,1.所有数都错位(缺了0);2.所有数都顺位(缺了最后一个数)。
技巧总结:看到有序数组——>二分/双指针——>既是查找问题,某种情况下也能作为判断某个数是否存在的问题

//第一种思路的实现:
//执行用时:1 ms, 在所有 Java 提交中击败了7.11% 的用户
//内存消耗:38.8 MB, 在所有 Java 提交中击败了98.45% 的用户
class Solution {
    public int missingNumber(int[] nums) {
        int n = nums.length+1;
        int[] A = new int[n];
       // int temp;
        Arrays.fill(A,-1);
        for(int i = 0;i < n-1;i++){
            // temp = nums[i];
            // A[temp] = nums[i];
            A[nums[i]] = nums[i];
        }
        for(int j = 0;j < n;j++){
            if(A[j]==-1){
                return j;
            }
        }
        return 0;
    }
}
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:38.8 MB, 在所有 Java 提交中击败了98.56% 的用户
class Solution {
    public int missingNumber(int[] nums) {
        int i = 0, j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            if(nums[m] == m) i = m + 1;
            else j = m - 1;
        }
        return i;
    }
}


作者:jyd
链接:https://leetcode-cn.com/problems/que-shi-de-shu-zi-lcof/solution/mian-shi-ti-53-ii-0n-1zhong-que-shi-de-shu-zi-er-f/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

【DAY24——数组专题】
第十一题:最小的K个数(Top-k)
在这里插入图片描述
分析:这种求top-k的,一半可以用快排、堆、冒泡这种不用排完序就知道最值的排序来解决。

//第一种方法:大根堆/小根堆(java默认大根堆,python默认小根堆),假如说新来的节点比堆的根节点还大,那么就不入堆,否则入堆然后重新排树,最后留下的就是最小的个数。
class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        int[] vec = new int[k];
        if (k == 0) { // 排除 0 的情况
            return vec;
        }
        PriorityQueue<Integer> queue = new PriorityQueue<Integer>(new Comparator<Integer>() {
            public int compare(Integer num1, Integer num2) {
                return num2 - num1;
            }
        });
        for (int i = 0; i < k; ++i) {
            queue.offer(arr[i]);
        }
        for (int i = k; i < arr.length; ++i) {
            if (queue.peek() > arr[i]) {
                queue.poll();
                queue.offer(arr[i]);
            }
        }
        for (int i = 0; i < k; ++i) {
            vec[i] = queue.poll();
        }
        return vec;
    }
}


作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/solution/zui-xiao-de-kge-shu-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
//第二种思路:快排的优化。
class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        randomizedSelected(arr, 0, arr.length - 1, k);
        int[] vec = new int[k];
        for (int i = 0; i < k; ++i) {
            vec[i] = arr[i];
        }
        return vec;
    }

    public void randomizedSelected(int[] arr, int l, int r, int k) {
        if (l >= r) {
            return;
        }
        int pos = randomizedPartition(arr, l, r);
        int num = pos - l + 1;
        if (k == num) {
            return;
        } else if (k < num) {
            randomizedSelected(arr, l, pos - 1, k);
        } else {
            randomizedSelected(arr, pos + 1, r, k - num);
        }
    }

    // 基于随机的划分
    public int randomizedPartition(int[] nums, int l, int r) {
        int i = new Random().nextInt(r - l + 1) + l;
        swap(nums, r, i);
        return partition(nums, l, r);
    }

    public int partition(int[] nums, int l, int r) {
        int pivot = nums[r];
        int i = l - 1;
        for (int j = l; j <= r - 1; ++j) {
            if (nums[j] <= pivot) {
                i = i + 1;
                swap(nums, i, j);
            }
        }
        swap(nums, i + 1, r);
        return i + 1;
    }

    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}


作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/solution/zui-xiao-de-kge-shu-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值