leetcode-hot100-普通数组:53最大子数组和-56合并区间-189轮转数组-238除了自身以外数组的乘积-41缺失的第一个正数

53最大子数组和

题目:给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。子数组是数组中的一个连续部分。

此题是贪心算法。局部最优:当前"连续和"为负数的时候立刻放弃,从下一个元素重新计算"连续和",因为负数加上下一个元素 "连续和"只会越来越小。

全局最优:选取最大"连续和"

局部最优的情况下,并记录最大的"连续和",可以推出全局最优。

从代码角度上来讲:遍历 nums,从头开始用 count 累积,如果 count 一旦加上 nums[i]变为负数,那么就应该从 nums[i+1]开始从 0 累积 count 了,因为已经变为负数的 count,只会拖累总和。

区间终止位置不用调整么? 如何才能得到最大"连续和"呢?区间的终止位置,其实就是如果 count 取到最大值了,及时记录下来了。

java 复制代码
class Solution {
    public int maxSubArray(int[] nums) {
        int result=Integer.MIN_VALUE;
        int count=0;
        for(int i=0;i<nums.length;i++){
            count=count+nums[i];
            result=count>result?count:result;
            if(count<0){
                count=0;
            }
        }
        return result;
    }
}

56合并区间

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。

示例 1:输入:intervals = [[1,3],[2,6],[8,10],[15,18]],输出:[[1,6],[8,10],[15,18]]

解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6]

先排序,让所有的相邻区间尽可能的重叠在一起,按左边界,或者右边界排序都可以,处理逻辑稍有不同。按照左边界从小到大排序之后,如果 intervals[i][0] <= intervals[i - 1][1] 即intervals[i]的左边界 <= intervals[i - 1]的右边界,则一定有重叠。(本题相邻区间也算重贴,所以是<=)

如何去模拟合并区间呢?其实就是用合并区间后左边界和右边界,作为一个新的区间,加入到result数组里就可以了。如果没有合并就把原区间加入到result数组。

java 复制代码
class Solution {
    public int[][] merge(int[][] intervals) {
        List<int[]> result=new LinkedList<>();
        Arrays.sort(intervals,(x,y)->Integer.compare(x[0],y[0]));

        int start=intervals[0][0];
        int right=intervals[0][1];

        for(int i=1;i<intervals.length;i++){
            if(intervals[i][0]>right){
                result.add(new int[]{start,right});
                start=intervals[i][0];
                right=intervals[i][1];
            }else{
                right=Math.max(right,intervals[i][1]);
            }
        }
        result.add(new int[]{start,right});
        return result.toArray(new int[result.size()][]);
    }
}

189轮转数组

题目:给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

示例 1:输入: nums = [1,2,3,4,5,6,7], k = 3,输出: [5,6,7,1,2,3,4]

解释:向右轮转 1 步: [7,1,2,3,4,5,6]

向右轮转 2 步: [6,7,1,2,3,4,5]

向右轮转 3 步: [5,6,7,1,2,3,4]

直接做开辟新空间:

java 复制代码
class Solution {
    public void rotate(int[] nums, int k) {
        int[] result=new int[nums.length];
        for(int i=0;i<nums.length;i++){
            result[(i+k)% nums.length]=nums[i];
        }
        System.arraycopy(result,0,nums,0,nums.length);
    }
}

语法补充:System.arraycopy(newArr, 0, nums, 0, n);的解释

newArr 是源数组。nums 是目标数组。n 是一个整数,表示要复制的元素个数。

srcPos = 0:从源数组 newArr 的索引 0(第一个元素)开始复制。

destPos = 0:从目标数组 nums 的索引 0(第一个位置)开始粘贴。

length = n:总共复制 n 个元素。

整体作用:将 newArr 的前 n 个元素复制到 nums 的前 n 个位置,相当于用 newArr 的前 n 个元素覆盖 nums 的前 n 个元素。

使用数组翻转:

原理如下,以示例一为例:

java 复制代码
class Solution {
    public void rotate(int[] nums, int k) {
        int n=nums.length;
        k=k%n;
        reverse(nums,0,n-1);
        reverse(nums,0,k-1);
        reverse(nums,k,n-1);
    }

    private void reverse(int[] nums,int i,int j){
        while(i<j){
            int temp=nums[i];
            nums[i]=nums[j];
            i++;
            nums[j]=temp;
            j--;
        }
    }
}

238除了自身以外数组的乘积

题目:给你一个整数数组 nums,返回数组 answer ,其中 answer[i] 等于 nums 中除了 nums[i] 之外其余各元素的乘积 。题目数据保证数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位整数范围内。请不要使用除法,且在 O(n) 时间复杂度内完成此题。

示例 1: 输入: nums = [1,2,3,4],输出: [24,12,8,6]

使用双指针,左边就是nums[i]左边所有元素的乘积,右边就是nums[i]右边所有元素的乘积。用一个数组来同时操作两端。

java 复制代码
class Solution {
    public int[] productExceptSelf(int[] nums) {
        int n=nums.length;
        int[] result=new int[n];
        Arrays.fill(result,1);

        int leftnum=1;
        int rightnum=1;
        for(int i=0,j=n-1;i<n;i++,j--){
            result[i]=result[i]*leftnum;
            result[j]=result[j]*rightnum;
            leftnum=leftnum*nums[i];
            rightnum=rightnum*nums[j];
        }

        return result;
    }
}

41缺失的第一个正数

题目:给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

示例 1:输入:nums = [1,2,0],输出:3

解释:范围 [1,2] 中的数字都在数组中。

示例 2:输入:nums = [3,4,-1,1],输出:2

解释:1 在数组中,但 2 没有。

原地哈希方法。它的核心思想是:利用数组的下标来标记数字是否出现过。

对于一个长度为 n 的数组,缺失的最小正整数一定在 1 到 n+1 之间。为什么?

如果数组包含了 1,2,3,...,n 这全部 n 个正整数,那么答案就是 n+1。否则,至少有一个 1~n 之间的数缺失,答案就是那个最小的缺失数。因此我们只需要关心数组中的数字是否在 [1, n] 范围内,对于小于等于 0 或大于 n 的数字可以忽略。

我们可以把数组想象成有 n 个座位,编号从 0 到 n-1。每个座位应该坐一个学号,学号 k 应该坐在座位 k-1 上(因为下标从 0 开始)。比如学号 1 应该坐在座位 0,学号 2 坐在座位 1,依此类推。

目标:通过交换,把所有在 [1, n] 范围内的数字放到它们"应该"在的位置上。这样,如果某个座位上的学号与座位编号不匹配,就说明那个学号缺失了。

nums 中可能有重复元素。假设 nums=[1,1,2]。从 nums[1] 开始。这个座位上的学生坐在正确的座位上。继续遍历,nums[2]=1,这是 1 号学生的影分身。由于 1 号学生的真身已经坐在正确的座位上,我们可以在第二次遍历中知道「数组中有 1」这个信息,所以可以忽略 nums[2],向后遍历。

条件 nums[nums[i] - 1] != nums[i] 是为了避免死循环:如果目标位置已经是对的数字,说明当前数字其实已经有一个副本在正确位置(例如数组中有重复数字),那么交换没有意义,直接跳过。实际上,如果当前数字和它目标位置的数字相等,就不需要交换。

java 复制代码
class Solution {
    public int firstMissingPositive(int[] nums) {
        int n=nums.length;
        for(int i=0;i<n;i++){
            while(1<=nums[i] && nums[i]<=n && nums[nums[i]-1]!=nums[i]){
                int j=nums[i]-1;
                int temp=nums[i];
                nums[i]=nums[j];
                nums[j]=temp;
            }
        }

        for(int i=0;i<n;i++){
            if(nums[i]!=i+1){
                return i+1;
            }
        }
        return n+1;
    }
}
相关推荐
客卿1232 小时前
力扣--组合,子集--回溯法的再探索--总结回溯法
java·算法·leetcode
_日拱一卒2 小时前
LeetCode(力扣):环形链表
算法·leetcode·链表
做怪小疯子2 小时前
Leetcode刷题——链表就地反转
算法·leetcode·链表
Eward-an3 小时前
高效构建长度为 n 的开心字符串中第 k 小的字符串
python·leetcode
样例过了就是过了4 小时前
LeetCode热题100 电话号码的字母组合
数据结构·c++·算法·leetcode·dfs
big_rabbit05025 小时前
[算法][力扣226]翻转一颗二叉树
数据结构·算法·leetcode
TracyCoder1235 小时前
LeetCode Hot100(65/100)——64. 最小路径和
算法·leetcode·职场和发展
Tisfy5 小时前
LeetCode 1415.长度为 n 的开心字符串中字典序第 k 小的字符串:DFS构造 / 数学O(n)
数学·算法·leetcode·深度优先·字符串·dfs·模拟
TracyCoder1235 小时前
LeetCode Hot100(62/100)——62. 不同路径
算法·leetcode·职场和发展