目录
53.最大子树和
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组
是数组中的一个连续部分。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1]
输出:1
示例 3:
输入:nums = [5,4,-1,7,8]
输出:23
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
public class Solution {
public int maxSubArray(int[] nums) {
if (nums == null || nums.length == 0) return 0;
int currentSum = nums[0]; // 当前子数组的和
int maxSum = nums[0]; // 到目前为止找到的最大子数组和
for (int i = 1; i < nums.length; i++) {//和为负数,则舍弃并重新开始计数
currentSum = Math.max(nums[i], currentSum + nums[i]);
maxSum = Math.max(maxSum, currentSum);
}
return maxSum;
}
}
dp
class Solution {
public int maxSubArray(int[] nums) {
int[] f = new int[nums.length];
f[0] = nums[0];
int ans = f[0];
for (int i = 1; i < nums.length; i++) {
f[i] = Math.max(f[i - 1], 0) + nums[i];
ans = Math.max(ans, f[i]);
}
return ans;
}
}
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].
示例 2:
输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
提示:
1 <= intervals.length <= 104
intervals[i].length == 2
0 <= starti <= endi <= 104
比较当前区间与上一区间是否有重叠
class Solution {
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals, (p, q) -> p[0] - q[0]); //升序
List<int[]> r = new ArrayList<>();
for (int[] p : intervals) { // 遍历所有区间
int l = r.size(); // l 表示当前存储的区间数量
// 如果当前区间的左端点小于等于最后一个合并区间的右端点,则它们重叠,需要合并
if (l > 0 && p[0] <= r.get(l - 1)[1]) r.get(l - 1)[1] = Math.max(r.get(l - 1)[1], p[1]);
//重叠,更新最后一个区间的右端点为两者中的最大值
else r.add(p);
// 没有重叠,将当前区间添加到结果中
}
return r.toArray(new int[r.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]
示例 2:
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释:
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]
提示:
1 <= nums.length <= 105
-231 <= nums[i] <= 231 - 1
0 <= k <= 105
直接三次反转
class Solution {
public void rotate(int[] nums, int k) {
int n = nums.length;
k %= n; // 轮转 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];
nums[j] = temp;
i++;
j--;
}
}
}
238.除自身以外乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。
题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。
请 不要使用除法,且在 O(n) 时间复杂度内完成此题。
示例 1:
输入: nums = [1,2,3,4]
输出: [24,12,8,6]
示例 2:
输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]
提示:
2 <= nums.length <= 105
-30 <= nums[i] <= 30
保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内
进阶:你可以在 O(1) 的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组 不被视为 额外空间。)
class Solution {
public int[] productExceptSelf(int[] nums) {
int l = nums.length;
if (l == 0) return new int[0];
int[] res = new int[l];// res[i] 存储的是 nums[i] 左侧所有元素的乘积
res[0] = 1; // 初始化 res[0] 为 1,因为第一个位置的左侧没有元素
int tmp = 1; // 用于存储右侧乘积的临时变量
//从左到右遍历,将每个位置 i 左侧的乘积存储到 res[i]
for (int i = 1; i < l; i++) res[i] = res[i - 1] * nums[i - 1];
// 从右到左遍历数组,使用变量 tmp 来累积右侧的乘积
for (int i = l - 2; i >= 0; i--) {
tmp *= nums[i + 1];
res[i] *= tmp;
}
return res;
}
}
41.缺失第一个正数h
给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。
请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。
示例 1:
输入:nums = [1,2,0]
输出:3
解释:范围 [1,2] 中的数字都在数组中。
示例 2:
输入:nums = [3,4,-1,1]
输出:2
解释:1 在数组中,但 2 没有。
示例 3:
输入:nums = [7,8,9,11,12]
输出:1
解释:最小的正数 1 没有出现。
提示:
1 <= nums.length <= 105
-231 <= nums[i] <= 231 - 1
public int firstMissingPositive(int[] nums) {
int l = nums.length;
// 只关心 [1, l] 范围内的数字,其他替换
for (int i = 0; i < l; ++i) {
if (nums[i] <= 0) nums[i] = l + 1;
}
// 不使用额外空间的方式,在原数组上标记哪些正整数已经出现了
// 将出现的正数对应的下标位置的数置为负数,标记 [1, l] 范围内出现过的数字
for (int i = 0; i < l; ++i) {
int num = Math.abs(nums[i]); // 获取当前数字的绝对值
if (num <= l) nums[num - 1] = -Math.abs(nums[num - 1]);
}
// 遍历数组,找到第一个大于 0 的数的位置,加 1 即为第一个缺失的正数
for (int i = 0; i < l; ++i) {
if (nums[i] > 0) return i + 1;
}
// 如果数组中的所有数字都对应位置的值被置为负数,说明 [1, l] 范围内的数字全部存在
return l + 1; // 返回 l + 1,即第一个缺失的正数
}
原地哈希可还行