注:p为leetcode顺序题号,o为leetcode上剑指offer第二版题号
p27 移除元素
题目:给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
链接:https://leetcode.cn/problems/remove-element/
思路:双指针
- p1从头到尾遍历
- 2.p2记录值不等于val
public int removeElement(int[] nums, int val) {
int n = nums.length, p2 = 0;
for (int p1 = 0; p1 < n; p1 ++) {
if (nums[p1] != val) {
nums[p2 ++] = nums[p1];
}
}
return p2;
}
p42 接雨水
/**
* 42. 接雨水
* 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
* https://leetcode-cn.com/problems/trapping-rain-water/
*/
/**
* @param {number[]} height
* @return {number}
*/
var trap = function(height) {
let n = height.length, res = 0
if (n === 0) return 0
// leftMax[i]:保存i左边的最大值 rightMax[i]:保存i右边的最大值
let leftMax = [], rightMax = []
// 处理两边界
leftMax[0] = height[0]
rightMax[n - 1] = height[n - 1]
// 从左往右遍历,找i左边的最大值
for (let i = 1; i < n; i ++) {
leftMax[i] = Math.max(leftMax[i - 1], height[i])
}
// 从右往左遍历,找i右边的最大值
for (let i = n - 2; i >= 0; i --) {
rightMax[i] = Math.max(rightMax[i + 1], height[i])
}
// 遍历求每个矩形上方的雨水量:min(左最大值,右最大值)减去当前高度值
for (let i = 0; i < n; i ++) {
res += Math.min(leftMax[i], rightMax[i]) - height[i]
}
return res
};
p54 螺旋矩阵
/**
* 54. 螺旋矩阵
* 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
* https://leetcode-cn.com/problems/spiral-matrix/
*/
/**
* @param {number[][]} matrix
* @return {number[]}
*/
var spiralOrder = function (matrix) {
const res = [], n = matrix.length, m = matrix[0].length,
// dx dy:定义4个方向 st:标记是否遍历过
dx = [0, 1, 0, -1], dy = [1, 0, -1, 0],
st = Array.from({length: n}, () => Array.from({length: m}, () => false))
if (n < 0) return res
// 从左上角开始遍历,x y:位置 d:方向
for (let i = 0, x = 0, y = 0, d = 0; i < n * m; i++) {
res.push(matrix[x][y]) // 遍历
st[x][y] = true // 标记
let a = x + dx[d], b = y + dy[d] //新的方向
// 判断条件:1.走到边界 2.已经遍历过
if (a < 0 || a >= n || b < 0 || b >= m || st[a][b]) {
d = (d + 1) % 4 // 方向变化
a = x + dx[d]
b = y + dy[d]
}
x = a
y = b
}
return res
};
p209 长度最小的子数组
题目:给定一个含有 n 个正整数的数组和一个正整数 target
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0
链接:https://leetcode.cn/problems/minimum-size-subarray-sum/
思路:滑动窗口
- 双指针 l r 分别表示滑动窗口的左右两端
- 窗口中的数之和sum<target时,r右移;否则l右移
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length, sum = 0;
int res = Integer.MAX_VALUE;
for (int l = 0, r = 0; r < n; r ++) {
sum += nums[r];
while (sum >= target) { // 注意边界条件
res = Math.min(res, r - l + 1);
sum -= nums[l ++];
}
}
return res == Integer.MAX_VALUE ? 0 : res;
}
p704 二分查找
题目:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
链接:https://leetcode.cn/problems/binary-search/
思路: 注意边界条件
- r = n - 1
- while (l <= r)
public int search(int[] nums, int target) {
int n = nums.length;
int l = 0, r = n - 1;
while(l <= r) { // 注意边界条件
int m = l + r >> 1;
if (nums[m] > target) {
r = m - 1;
} else if (nums[m] < target) {
l = m + 1;
} else {
return m;
}
}
return -1;
}
p997 有序数组的平方
题目:给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序排序。
链接:https://leetcode.cn/problems/squares-of-a-sorted-array/
思路:双指针
负数的平方可能会比正数的平方大
数组两头的平方值大于中间的平方值
1.l指向数组最左端;r指向数组最右端
2.i指向平方值结果数组,从最大值开始
public int[] sortedSquares(int[] nums) {
int n = nums.length;
int l = 0, r = n - 1, i = n - 1; // 结果数组索引
int[] res = new int[n]; // 结果数组
while (l <= r) {
if (nums[l] * nums[l] < nums[r] * nums[r]) {
res[i --] = nums[r] * nums[r --];
} else {
res[i --] = nums[l] * nums[l ++];
}
}
return res;
}
o3 数组中重复的数字
/**
* 剑指 Offer 03. 数组中重复的数字
* 找出数组中重复的数字。
* 在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。
* 数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。
* 请找出数组中任意一个重复的数字。
* https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/
*/
/**
* @param {number[]} nums
* @return {number}
*/
var findRepeatNumber = function(nums) {
let n = nums.length
// 遍历一遍,如果不在[0, n-1]范围内,返回-1
for (let x of nums) {
if (x < 0 || x >= n) return -1
}
// 遍历找重复数字
for (let i = 0; i < n; i ++) {
// 一共开辟n个位置,每个数存放在对应值的位置
// 如果当前位置的数不在其对应位置,则将当前位置的数与其应在的位置交换
while (nums[nums[i]] !== nums[i]) {
// [nums[i], nums[nums[i]]] = [nums[nums[i]], nums[i]] 不能这样用,会超时,应该把nums[nums[i]]放在前面,防止nums[i]先改变了
[nums[nums[i]], nums[i]] = [nums[i], nums[nums[i]]]
/* 或者可以先用一个临时变量把nums[i]存储起来
let temp = nums[i];
[nums[i], nums[temp]] = [nums[temp], nums[i]];
*/
}
// 交换完成后,如果当前位置的数还不在对应位置,说明有重复值,即该位置和其应在的位置
if (i !== nums[i]) return nums[i]
}
return -1 // 没有重复 返回-1
};
o39 数组中出现次数超过一半的数字
/**
* 剑指 Offer 39. 数组中出现次数超过一半的数字
* 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
* 你可以假设数组是非空的,并且给定的数组总是存在多数元素。
* https://leetcode-cn.com/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof/
*/
/**
* @param {number[]} nums
* @return {number}
* 思路:思路很奇特
* 如果一个数大于一半,这个数最后的数量肯定大于其他所有数的数量之和
* 如果当前数是所求数,count++;不是所求数,则count--
* 用非所求数来消耗所求数,消耗不完,最后剩下的数就是所求数
* 时间复杂度:O(n) 空间复杂度:O(1)
*
* y总说:创造一个新解法比回忆起一个解法难一万倍!要多刷题!
*/
var majorityElement = function(nums) {
let count = 0, value = -1
for (let x of nums) {
// 如果count===0,记录value,count++
if (!count) {
count ++
value = x
} else {
// count!==0 此时value值存在,判断value是否等于当前x,等于count增加,否则count消耗
if (value === x) count ++
else count --
}
}
return value
};