LeetCode热题100(Java)(5)普通数组

本章包括的题目有:

53. 最大子数组和 - 力扣(LeetCode)

56. 合并区间 - 力扣(LeetCode)

189. 轮转数组 - 力扣(LeetCode)

238. 除了自身以外数组的乘积 - 力扣(LeetCode)

41. 缺失的第一个正数 - 力扣(LeetCode)

1.最大子数组和

思路解析:

定义 dp[i] 表示以数组中第 i 个元素结尾的连续子数组的最大和(此处 i 从 1 开始,对应 nums[i-1])。初始时,dp[0] = 0 表示没有元素时的和为 0。遍历数组,对于每个位置 i,以 nums[i-1] 结尾的最大子数组和有两种选择:将当前元素接在前面的子数组后面,即 dp[i-1] + nums[i-1];从当前元素重新开始一个子数组,即 nums[i-1]。两者取较大值作为 dp[i],同时用变量 m 记录遍历过程中出现的最大值。遍历结束后,m 即为整个数组的最大子数组和。

代码实现:

java 复制代码
class Solution {
    public int maxSubArray(int[] nums) {
        int n = nums.length;
        int[] dp = new int[n+1];
        dp[0] = 0;
        int m = Integer.MIN_VALUE;

        for (int i = 1; i < n+1; i++) {
            dp[i] = Math.max(dp[i-1]+nums[i-1],nums[i-1]);
            if(dp[i]>m)m=dp[i];

        }
        return m;
    }
}

时间复杂度O(n)

空间复杂度O(n)

2.合并区间

思路解析:

有一种简单的思路,就是先把每个区间按第一个元素排一个序,然后每次比较最小的两个区间,如果最小的两个区间有重合的,就把它们合并成一个区间。然后再次用这个区间作为最小的区间,和后面的区间比较;如果最小的两个区间没有重合的,就把最小的那个区间放到结果数组里,把第二小的区间去和后面的区间比较。这样遍历完成,就能得到结果。

代码实现:

java 复制代码
import java.util.ArrayList;
import java.util.PriorityQueue;

class Solution {
    public int[][] merge(int[][] intervals) {
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
        int n = intervals.length;
        for (int i = 0; i < n; i++) {
            pq.add(intervals[i]);
        }
        ArrayList<int[]> ret = new ArrayList<>();
        int index = 0;
        while(!pq.isEmpty()){
            int[] arr1 = pq.poll();
            if(pq.isEmpty()){
                ret.add(arr1);
                index ++;
                break;
            }
            int[] arr2 = pq.poll();
            if(arr1[1] >= arr2[0]) {
                int[] arr3 = new int[2];
                arr3[0] = arr1[0];
                arr3[1] = Math.max(arr2[1],arr1[1]);
                pq.add(arr3);
            }else{
                ret.add(arr1);
                index ++;
                pq.add(arr2);
            }
        }
        int[][] ans = ret.toArray(new int[0][]);
        return ans;
    }
}

时间复杂度:O(n log n)

空间复杂度:O(n)

实现代码可以优化,因为每次将新的数组加入优先级队列的时候,都会产生额外的开销,可以考虑直接将优先级队列中的元素一个个取出来加添加到结果中,每次判定取出来的元素和前一个元素是否有重合部分,如果有的话,就更新前一个结果;没有的话就直接添加到结果数组中。

3.轮转数组

思路解析:

我们可以创建一个新的数组,来储存轮转之后的数组,然后将这个新的数组的值赋值给原来的数组返回就可以了。由于是轮转的原因,所以当k大于数组的长度时,可以对它的长度取模,因为转一圈相当于没转。

代码实现:

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

时间复杂度:O(n)

空间复杂度:O(n)

当然,我们也可以尝试空间复杂度更优的做法,我们先找到轮转的位置,然后对整个数组进行反转,再对轮转之前的位置进行反转,再对轮转及其之后的位置进行反转,就可以得到结果。

如图,我们假设k=3,进行反转之后就可以得到最后的结果,可以将空间复杂度优化到O(1)

4.除了自身以外数组的乘积

思路解析:

题目说不可以用除法,因此不能将所有的全部乘起来除当前数得到结果。我们计算除了自身以外数字的乘积,其实就是计算自己元素左边元素的累乘和右边元素的累乘之积。我们可以定义两个数组,一个数组 l 表示本元素及左边元素的累乘,一个数组 r 表示本元素及右边元素的累乘。因此结果就是结果数组的ret[i] = l[i - 1] * r [i + 1]。

代码实现:

java 复制代码
class Solution {
    public int[] productExceptSelf(int[] nums) {
        long[] l = new long[nums.length];
        long[] r = new long[nums.length];
        for(int i = 0; i < nums.length; i++){
            if(i != 0){
                l[i] = nums[i] * l[i - 1];
                r[nums.length - 1 - i] = nums[nums.length - 1 - i] * r[nums.length - i];
            }
            else {
                l[i] += nums[i];
                r[nums.length - 1 - i] += nums[nums.length - 1 - i];
            }
        }
        int[] ret = new int[nums.length];
        for(int i = 0; i < nums.length; i++){
            if(i == 0){
                ret[i] = (int)r[i + 1];
                continue;
            }
            if(i == nums.length - 1){
                ret[i] = (int)l[i - 1];
                continue;
            }
            ret[i] = (int)(l[i - 1] * r [i + 1]);
        } 
        return ret;
    }
}

时间复杂度:O(n)

空间复杂度:O(n)

我们同样可以尝试优化我们的空间复杂度,思路如下,我们不需要引入额外的两个累乘数组,而是直接将本位置左边累乘的结果存到结果数组中,第二遍循环,逆着更新结果数组的值即可(定义一个常数变量,记录从右边开始累乘的值,依次乘到结果数组中去),这样就可以将空间复杂度优化到O(1)。

5.缺失的第一个正数

思路解析:

由于题目要求时间复杂度:O(n), 空间复杂度:O(1),因此我们只能对原数组进行操作,且不能进行排序操作。由题意可以联想到用哈希的方法去依次寻找有没有对应的值,但是这里不允许有额外的 n 的空间的开销,因此我们只能利用原数组进行哈希。思路为遍历数组,每遍历到一个位置,得到那个数,就把它填到本该属于它的地方(例如把数字1填到位置0),但是由于这样做会覆盖这个地方它原本的数,所以我们需要定义变量去储存这个原本的数,再把原本的数放到它本该属于的地方,以此类推,直到1.它本该属于的地方不在数组的范围之内,可以跳出循环2.它本来就属于这里。这样操作过后,每个数字至多被判断两遍,且只有常数级的开销。

代码实现:

java 复制代码
class Solution {
    public int firstMissingPositive(int[] nums) {
        int pre = 0,cur = 0;
        for (int i = 0; i < nums.length; i++){
            if(nums[i] > nums.length || nums[i] < 1) continue;
            if(nums[nums[i] - 1] == nums[i])continue;
            else{
                cur = nums[i];
                while(true){
                    pre = cur;
                    if(pre - 1 < 0 || pre > nums.length || nums[pre - 1] == pre)break;
                    cur = nums[pre - 1];
                    nums[pre - 1] = pre;
                }

            }
        }
        for (int i = 0; i < nums.length; i++) {
            if(nums[i] != i + 1) return i + 1;
        }
        return nums.length + 1;
    }
}

上一章:

LeetCode热题100(Java)(4)子串-CSDN博客

下一章:

LeetCode热题100(Java)(6)矩阵-CSDN博客

相关推荐
旖-旎1 小时前
深搜练习(组合)(5)
c++·算法·深度优先·力扣
fzil0012 小时前
自动投递简历 + 面试进度跟踪
人工智能·面试·职场和发展
@小码农2 小时前
2026年3月Scratch图形化编程等级考试一级真题试卷
开发语言·数据结构·c++·算法
其实防守也摸鱼2 小时前
面试常问问题总结--护网蓝队方向
网络·笔记·安全·面试·职场和发展·护网·初级蓝队
Wect2 小时前
LeetCode 5. 最长回文子串:DP + 中心扩展
前端·算法·typescript
糖果店的幽灵2 小时前
决策树详解与sklearn实战
算法·决策树·sklearn
Lewiis2 小时前
趣谈排序算法
算法·排序算法
ComputerInBook3 小时前
数字图像处理(4版)——第 8 章——图像压缩与水印(上)(Rafael C.Gonzalez&Richard E. Woods)
人工智能·算法·计算机视觉·图像压缩·图像水印
前端百草阁3 小时前
【吃透 Promise】从基础到面试高频(手写 + 输出题 + 原理)
okhttp·面试·职场和发展