3.30代码随想录二刷——移除元素系列、长度最小的子数组系列
移除元素
283.移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]
输出: [0]
思路
用双指针i,j,i遍历原数组,遇到非零元素。
j遍历有效数组,将i非零的元素补进来
剩下的补0
题解
class Solution {
public void moveZeroes(int[] nums) {
if (nums.length == 0) {
return;
}
//第一次遍历,j指针记录非0的个数,只要是非0的统统都赋给nums[j]
int j = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] != 0){
nums[j] = nums[i];
j++;
}
}
//非0元素统计完了,剩下的都赋0即可
for (int i = j; i < nums.length; i++) {
nums[i] = 0;
}
}
}
844.比较含退格的字符串
给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。
**注意:**如果对空文本输入退格字符,文本继续为空。
示例 1:
输入:s = "ab#c", t = "ad#c"
输出:true
解释:s 和 t 都会变成 "ac"。
示例 2:
输入:s = "ab##", t = "c#d#"
输出:true
解释:s 和 t 都会变成 ""。
示例 3:
输入:s = "a#c", t = "b"
输出:false
解释:s 会变成 "c",但 t 仍然是 "b"。
思路
用双指针i,j来遍历两字符串,同时sSkipNum、tSkipNum记录两个字符串的"#",遇到时++,没遇到时,如果其值>0 则进行–,当该值<0,则跳出对于s,t的模拟消除过程。最后比对两字符串各元素
题解
class Solution {
public boolean backspaceCompare(String s, String t) {
//844比较含退格的字符串
//由后向前遍历,记录#的数量,模拟消除的操作,如果#用完了,就开始比较S[i]和t[j]
int i = s.length() - 1;
int j = t.length() - 1;
int sSkipNum = 0;//记录S中#的数量
int tSkipNum = 0;//记录t中#的数量
while (true){
//先统计,并模拟消除
while (i >= 0){
if (s.charAt(i) == '#'){
sSkipNum++;
}else {
if (sSkipNum > 0){
sSkipNum--;
}else {
break;
}
}
i--;
}
while (j >= 0){
if (t.charAt(j) == '#'){
tSkipNum++;
}else {
if (tSkipNum > 0){
tSkipNum--;
}else {
break;
}
}
j--;
}
//再比对,比较s[i] 和 t[j]
if(i < 0 || j < 0){
break;//S或者T遍历到头
}
if(s.charAt(i) != t.charAt(j)){
return false;
}
i--;
j--;
}
//说明S,T同时遍历完毕
if (i == -1 && j == -1){
return true;
}
return false;
}
}
977.有序数组的平方
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
示例 2:
输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]
思路
方法一:直接平方, 排序
方法二:利用 最大值总会在两端,双指针ij,对两边界比较,取最大值,填入新数组终止位置。
题解
public class SortedSquares {
public int[] sortedSquares(int[] nums) {
//977.有序数组的平方
//第一种方法:平方后直接排序
// for (int i = 0; i < nums.length; i++) {
// nums[i] = nums[i] * nums[i];
// }
//
// Arrays.sort(nums);
//第二种方法:双指针
//再新建一个数组res
int[] res = new int[nums.length];
int k = nums.length - 1;
//平方后,数组的最大值一定会是在两端,不会在中间,所以用ij双指针遍历比较nums,用k表res终止位置依次填入最大值
for (int i = 0,j = nums.length - 1; i <= j ; ) {
if (nums[i] * nums[i] > nums[j] * nums[j]) {
res[k] = nums[i] * nums[i];
k--;
i++;
}else {
res[k] = nums[j] * nums[j];
k--;
j--;
}
}
return res;
}
}
长度最小的子数组
209.长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度**。**如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4]
输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
思路
用滑动窗口,其实也是双指针,就是将元素和>=target的限定为一个窗口里,然后一直求最小的窗口
题解
public class MinSubArrayLen {
public int minSubArrayLen(int target, int[] nums) {
int minLen = Integer.MAX_VALUE;//用于统计满足条件的子数组的最小长度
int sum = 0;//用于求和
int i = 0;//作为滑动窗口开始位置
for (int j = 0; j < nums.length; j++) {
sum += nums[j];
while (sum >= target){//当元素之和大于target,记录下此时的长度,移动窗口接着求
minLen = Math.min(minLen,j - i + 1);
sum -= nums[i];
i++;//滑动窗口开始位置往前
}
}
//如果minLen没有被赋值,则返回0
return minLen == Integer.MAX_VALUE ? 0:minLen;
}
}
904.水果成篮
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。
你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:
- 你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
- 你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
- 一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。
示例 1:
输入:fruits = [1,2,1]
输出:3
解释:可以采摘全部 3 棵树。
示例 2:
输入:fruits = [0,1,2,2]
输出:3
解释:可以采摘 [1,2,2] 这三棵树。
如果从第一棵树开始采摘,则只能采摘 [0,1] 这两棵树。
思路
题解
待续。。。下一篇接上
本文介绍了几个基于数组的算法问题,包括如何原地移动数组中的零到末尾,比较含退格的字符串是否相等,有序数组的平方以及找到和大于等于目标值的最小子数组的长度。这些问题都采用了双指针或滑动窗口的策略来解决。

被折叠的 条评论
为什么被折叠?



