代码随想录Java

记录并分享一些代码随想录中有趣的题目

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值