记录并分享一些代码随想录中有趣的题目
27.移除元素
给你一个数组 nums
和一个值 val
,你需要 原地 移除所有数值等于 val
的元素。元素的顺序可能发生改变。然后返回 nums
中与 val
不同的元素的数量。
假设 nums
中不等于 val
的元素数量为 k
,要通过此题,您需要执行以下操作:
- 更改
nums
数组,使nums
的前k
个元素包含不等于val
的元素。nums
的其余元素和nums
的大小并不重要。 - 返回
k
。
暴力解决,O(n2)
双指针(快慢指针)
// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
if (val != nums[fastIndex]) {
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;
}
};
slowIndex:慢指针,新数组的下一个插入位置(即当前不等于val的元素应该放的位置)
fastIndex:快指针,用于遍历整个数组
首先理解概念,slowIndex就是可以插入的位置,这是定义。所以遇到了合适的nums[fastIndex]!=val;就得把这个值插进去。fastIndex是从左到右对于每个值进行遍历,遇到合适的(不等于val)就插到前面去(注意快指针永远大于或等于慢指针),遇到等于val的不去管它,只找合适的插就行,因为val会被慢指针覆盖掉。
扩展:
双指针:同时使用两个指针来遍历数据结构,常见的有:
-
对撞指针:一个指针从数组的开始位置出发,另一个指针从数组的末尾出发,向中间移动。通常用于解决排序数组中的两数之和、查找回文等问题。
-
左右指针:两个指针从左到右或从右到左同时进行遍历。常用于滑动窗口问题,例如寻找子数组或字符串中的特定元素
快慢指针是一种特殊的双指针技巧,通常用于链表中,解决涉及循环检测、找到链表的中间节点等问题。
- 快指针:每次移动两个节点或两个元素。
- 慢指针:每次移动一个节点或一个元素。
这种方法的核心思想是,通过快慢指针的不同速度来缩短寻找的时间或检测链表的某种特性。
977.有序数组的平方
给你一个按 非递减顺序 排序的整数数组 nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
输入:nums = [-4,-1,0,3,10] 输出:[0,1,9,16,100] 解释:平方后,数组变为 [16,1,0,9,100] 排序后,数组变为 [0,1,9,16,100]
一个有正有负的数组,从0分左右,负数绝对值------》越来越小,正数绝对值-------》越来越大
并且也是有序的。这不禁让我想起了一个经典的有序数组合并问题,是这样的没错!
双指针left=0;right=nums.length-1;找二者之间较大值填到新数组对应位置。
知道两个数组相遇了,填上最后一个数,结束循环。
因为这是一个数组,所以最后会相遇;两个数组的话一个遍历完了,还得把另一个数组加到新数组尾部。
class Solution {
public int[] sortedSquares(int[] nums) {
int right = nums.length - 1;
int left = 0;
int[] result = new int[nums.length]; //新的空数组
int index = result.length - 1; //新数组要插补的位置
while(left <= right){
if (nums[left]*nums[left] > nums[right]*nums[right]){
//把大的放新数组对应位置index
result[index]=nums[left]*nums[left];
left ++;
index--;//指针移位
}
else{
result[index]=nums[right]*nums[right];
right--;
index--;//指针移位
}
}
return result;
}
}
209.长度最小的子数列
给定一个含有 n
个正整数的数组和一个正整数 target
。
找出该数组中满足其总和大于等于 target
的长度最小的
子数组
[numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回 0
。
滑动窗口是一种常见的双指针技巧,用于解决子数组或子串(注意,是在数组或串中摘一个完整的子数组,不是挨个挑)的问题。
滑动窗口算法左指针left,右指针right,定义了当前的窗口。窗口的内容就是指针之间的元素。右指针右移扩大窗口,将新元素加入窗口。左指针右移缩小窗口,这通常用于寻找满足条件的最小窗口。
首先明确定义
窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组
窗口的起始位置如何移动:
如果当前窗口的值大于等于s了,窗口要缩小了,左指针前移;
否则,窗口要扩大了,右指针前移;
其间,记录最小的窗口值并不断更新。当右指针指向nums.length-1结束,返回最小窗口值。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left = 0;//左指针
int right = 0;//右指针
if(nums[0]==target){
return 1;
}
for(int i =0;i<nums.length;i++){
}
int min_window=Integer.MAX_VALUE;//最小窗口
int sum = 0;//当前窗口里数的和
for(;right<nums.length;right++) //右指针将窗口扩到数组末尾,循环结束
{
sum = sum+nums[right]; //将新值加入窗口
while(sum >= target){
min_window = Math.min(min_window,right-left+1);//最小
sum = sum - nums[left];//试图找满足条件的最小窗口
left++;//缩小窗口
}
}
return min_window < Integer.MAX_VALUE ? min_window:0;
}
}
58.
区间和(第九期模拟笔试)
题目描述
给定一个整数数组 Array,请计算该数组在每个指定区间内元素的总和。
输入描述
第一行输入为整数数组 Array 的长度 n,接下来 n 行,每行一个整数,表示数组的元素。随后的输入为需要计算总和的区间下标:a,b (b > = a),直至文件结束。
输出描述
输出每个指定区间内元素的总和。
输入示例
5
1
2
3
4
5
0 1
1 3
输出示例
3
9
import java.util.Scanner;//导入 Scanner 类,读取各种类型的输入,包括整数、字符串、浮点数等。
public class Main{
public static void main (String[] args) {
Scanner scanner = new Scanner(System.in);
//创建一个 Scanner 对象的语句,这个对象可以从控制台(标准输入流)读取用户输入
int n = scanner.nextInt();
int[] vec = new int[n];
int[] p = new int[n];
int presum = 0;
for(int i=0;i<n;i++){
vec[i]=scanner.nextInt();//nextInt() 用于读取下一个整数(int 型)输入,读字符串nextLine()
}
for(int i=0;i<n;i++){
presum=presum+vec[i];
p[i] = presum;
}
while(scanner.hasNextInt()){
int a=scanner.nextInt();
int b=scanner.nextInt();
if(a<=b){
if(a==0){
System.out.println(p[b]);
}
else{
int temp= p[b]-p[a-1];
System.out.println(temp);
}
}
}
scanner.close();
}
}
这是一道很简单的题目,每次查询然后遍历求和输出就行了,时间复杂度O(m*n)
但是考虑到m*n可能会很大,遍历很多次时间复杂度太高,我们想重复利用已经计算过的子数组之和---》前缀和思想
vec[n] 数据数组
p[n]从0到n索引的数据之和
任意区间[a,b],元素之和=p[b]-p[a-1];//包括vec[a]也包括vec[b]
java