【刷题记录】

27.移除元素

快慢指针解法

快指针遍历整个数组:快指针遍历数组的每个元素,判断该元素是否等于给定val
如果快指针遍历到的元素不等于val,则将其赋值给慢指针位置

慢指针用于记录不等于val的元素的位置
当快指针遍历到不等于val的元素时,慢指针才需要+1,以确保不等于val的元素保留在数组前面
慢指针的值即为数组中不包含val的元素数量

public int removeElment(int[] nums,int val){
		int slow = 0;
		 for(int fast = 0;fast<nums.length;fast++){
			 if(nums[fast] != val){
				 nums[slow] = nums[fast];
				 slow++;
			 }
		 }
		 return slow
	}

暴力双层循环解法

外层循环:遍历整个数组,找到需要移除的元素val
内层循环:一旦找到val,就把它后面的元素前移,覆盖当前的val

public int removeElment(int[] nums,int val){
	int n = nums.lenght;
	for(int i = 0;i < n;i++){
		if(nums[i] == val){
			for(int j = i;j<n-1;j++){//内层循环,后面的元素前移
				nums[j] = nums[j + 1];
			}
			n--;//数组长度减一
			i--;//继续检查当前位置,防止新移过来的元素被跳过
		}
	}
	return n;
}

数组 = 3,2,2,4,5
value = 2
外层循环,首先遍历到i=1,发现数组 i = 2,这就是我们要移除的元素
进入内层循环,将后面的元素逐个向前移
数组i = 2后面的元素的值逐个向前移动
num 1会被 num 2的值2替代 3,2,2,4,5
num 2会被 num 3的值2替代 3,2,4,4,5
num 3会被 num 4的值2替代 3,2,4,5,5
3,4,5,5,5

26.删除有序数组中的重复项

在重复项的位置覆盖元素

去重,默认第一个元素一定是唯一的thats why slow=1

题目要求

  1. 原地去重:不能使用额外的数组,必须在nums本身修改
  2. 保持相对顺序
  3. 返回唯一元素的个数k,并让nums的前k个元素存放去重后的值

快慢指针的作用

  1. 快指针fast

    • 负责遍历数组,找到不重复的元素
    • 遇到不相等的值,就告诉慢指针存储该值
  2. 慢指针slow

    • 负责存放唯一的元素,保证去重后元素紧凑存储在nums的前k个位置
    • 每当fast发现新元素,就写入nums【slow】,并移动slow指向下一个可存放的位置
class Solution {
    public int removeDuplicates(int[] nums) {
        int slow = 1;  // 慢指针:指向存放新元素的位置
        for (int fast = 0; fast < nums.length - 1; fast++) {  // 快指针遍历整个数组
            if (nums[fast] != nums[fast + 1]) {  // 找到新的不同的数
                nums[slow] = nums[fast + 1];  // 放到 slow 指针的位置
                slow++;  // 慢指针移动
            }
        }
        return slow;  // slow 代表唯一元素的个数 k
    }
}

2460.对数组执行操作

双指针解决

class Solution {
    public int[] applyOperations(int[] nums) {
        // 1. 先合并相邻相同的数
        for (int i = 0; i < nums.length - 1; i++) {
            if (nums[i] == nums[i + 1]) {
                nums[i] *= 2;  // 合并
                nums[i + 1] = 0;  // 置 0
            }
        }
        
        // 2. 移动零(使用嵌套循环)
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == 0) {  // 找到 0
                for (int j = i + 1; j < nums.length; j++) {  
                    if (nums[j] != 0) {  // 找到后面的非零元素
                        // 交换 nums[i] 和 nums[j]
                        int temp = nums[i];
                        nums[i] = nums[j];
                        nums[j] = temp;
                        break;  // 交换一次就跳出内循环
                    }
                }
            }
        }

        return nums;
    }
}

118.杨辉三角

1295. 统计位数为偶数的数字

Java如何将数字转换为字符串


法一:使用String.valueOf()

int num = 123;
String str = String.valueOf(num);

法二:使用Integer.toString()
专门用于将整数转换为字符串

int num = 456;
String str = Integer.toString(num);

法三:使用字符串拼接
通过将数字与空字符串""拼接,Java会自动将数字转换为字符串

int num = 789
String str = num + "";

for(int num:nums)是Java中的增强for循环(for-each循环)一种简化遍历数组或集合的语法
适合只需要访问数组或集合中的每个元素,而不需要操作索引时


增强for循环的语法

for(元素类型 变量名 : 数组或集合名){
	//使用变量名操作当前元素
}
  • 元素类型:数组或集合中元素的类型(int, String)
  • 变量名:一个临时变量名,用于存储当前遍历到的元素
  • 数组或集合:需要遍历的数组或集合

区别:

特性增强 for 循环普通 for 循环
语法简洁性更简洁,适合遍历数组或集合中的元素需要手动管理索引,语法稍复杂
索引访问无法直接访问索引可以通过索引访问元素
修改数组或集合只能读取元素,不能修改数组或集合可以通过索引修改数组或集合中的元素
适用场景适合只读遍历适合需要索引操作的场景

使用场景

  1. 遍历数组:
int[] nums = {1,2,3,4,5};
for(int num:nums){
	sysyout(num);
}
  1. 遍历集合
List<String> list = Arrays.asList("A","B","C");
for(String str : list){
	sysout(str);
}
  1. 遍历多维数组
int[][] matrix = {{1,2},{3,4}};
for(int[] row : matrix){
	for(int num : nums){
		sysout(num);
	}
}

题目解决

class Solution(int[] nums){
	int count = 0
	for(int num : nums){
		String str = String.valueOf(num);
		if(str.length() % 2 == 0){
			count++;
		}
	}
	return count;
}

2094. 找出 3 位偶数

349. 两个数组的交集


List<Integer> resultList = new ArrayList<>(); 是 Java 中创建列表(List)的一种方式。


1. List<Integer> 是什么?

List 是 Java 中的一个接口,表示一个有序的集合(也称为序列)。它可以存储多个元素,并且允许重复元素。List 接口的常见实现类有 ArrayListLinkedList 等。

  • Integer:这是 List 中存储的元素类型。Integer 是 Java 中的包装类,用于表示基本数据类型 int 的对象形式。
  • List<Integer>:表示一个可以存储 Integer 类型元素的列表。

2. ArrayList<>() 是什么?

ArrayListList 接口的一个实现类。它是一个基于动态数组的数据结构,支持快速随机访问和动态扩容。

  • new ArrayList<>():这是创建 ArrayList 对象的语法。<> 是 Java 中的泛型语法,表示这个列表可以存储任意类型的元素。在这里,<> 中的类型被推断为 Integer,因为前面已经声明了 List<Integer>

3. List<Integer> resultList = new ArrayList<>(); 的作用

这行代码的作用是创建一个名为 resultList 的列表,用于存储 Integer 类型的元素。这个列表可以用来动态地添加、删除或访问元素。

  • 动态大小ArrayList 的大小是动态的,可以根据需要自动扩容。
  • 有序性:列表中的元素是有序的,按照添加的顺序存储。
  • 允许重复:列表中可以存储重复的元素。

4. 为什么在这里使用 List<Integer>

在你的代码中,resultList 用于存储两个数组的交集结果。使用 List<Integer> 的原因包括:

  • 动态添加元素:在找到交集元素时,可以方便地使用 resultList.add(num) 将元素添加到列表中。
  • 去重:可以通过 resultList.contains(num) 检查元素是否已经存在于列表中,从而避免重复添加。
  • 最终转换为数组:在返回结果时,可以将 List<Integer> 转换为 int[],方便返回。

5. List<Integer> 的常用方法

以下是一些 List<Integer> 的常用方法:

  • add(Integer element):向列表中添加一个元素。
  • contains(Object element):检查列表中是否包含某个元素。
  • get(int index):获取列表中指定位置的元素。
  • size():返回列表中元素的数量。
  • remove(Object element):从列表中移除某个元素。

6. 示例代码

以下是一个简单的示例,展示如何使用 List<Integer>

import java.util.ArrayList;
import java.util.List;

public class Example {
    public static void main(String[] args) {
        // 创建一个 List<Integer>
        List<Integer> numbers = new ArrayList<>();

        // 添加元素
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);

        // 检查是否包含某个元素
        System.out.println("Contains 2? " + numbers.contains(2)); // 输出: true

        // 获取元素
        System.out.println("Element at index 1: " + numbers.get(1)); // 输出: 2

        // 遍历列表
        for (int num : numbers) {
            System.out.println(num);
        }
    }
}

1351. 统计有序矩阵中的负数

Java 数组系统教程

一、一维数组

1. 声明与初始化
Java 数组是固定长度的容器,存储相同类型的元素。

// 声明方式(两种等价)
int[] arr1;    // 推荐
int arr2[];    // 不推荐,易与变量名混淆

// 初始化方式
int[] arr3 = {1, 2, 3};               // 直接赋值(静态初始化)
int[] arr4 = new int[3];              // 动态初始化(默认值为0)
int[] arr5 = new int[]{1, 2, 3};      // 动态初始化(需显式赋值)

2. 访问与遍历
通过索引访问数组元素(索引从 0 开始):

System.out.println(arr3[0]);   // 输出 1
arr4[1] = 5;                  // 修改元素

// 遍历方式(三种)
// 1. for 循环
for (int i = 0; i < arr3.length; i++) {
    System.out.println(arr3[i]);
}

// 2. for-each 循环(只读遍历)
for (int num : arr3) {
    System.out.println(num);
}

// 3. 使用 Arrays.toString()
System.out.println(Arrays.toString(arr3));  // 输出 [1, 2, 3]

二、二维数组

1. 声明与初始化
二维数组是“数组的数组”,每行可以有不同的长度(但题目中的矩阵通常等长)。

// 声明方式
int[][] matrix1;                  // 推荐
int matrix2[][];                  // 不推荐

// 初始化方式
int[][] matrix3 = {{1, 2}, {3, 4, 5}};    // 静态初始化(允许不等长)
int[][] matrix4 = new int[2][3];          // 动态初始化(等长矩阵)
int[][] matrix5 = new int[][]{{1}, {2, 3}}; 

2. 访问与遍历

// 访问元素
System.out.println(matrix3[0][1]);   // 输出 2

// 遍历二维数组(正确方式)
for (int i = 0; i < matrix3.length; i++) {          // 遍历行
    for (int j = 0; j < matrix3[i].length; j++) {   // 遍历当前行的列
        System.out.print(matrix3[i][j] + " ");
    }
    System.out.println();
}

关键点:

  • matrix.length 表示行数。
  • matrix[i].length 表示第 i 行的列数。

三、常见错误与解决方法

1. 数组越界(ArrayIndexOutOfBoundsException)

int[] arr = {1, 2, 3};
System.out.println(arr[3]);  // ❌ 索引最大为2

解决方法: 确保索引 < arr.length

2. 空指针异常(NullPointerException)

int[][] matrix = new int[2][];
System.out.println(matrix[0][0]);  // ❌ matrix[0] 未初始化,为null

解决方法: 初始化每一行:

for (int i = 0; i < matrix.length; i++) {
    matrix[i] = new int[3];  // 每行初始化3列
}

3. 遍历条件错误
用户原代码错误:

for (int j = 0; j < grid.length; j++)  // ❌ 错误使用行数作为列循环条件

修正:

for (int j = 0; j < grid[i].length; j++)  // ✅ 使用当前行的列数

四、性能优化(针对题目)

题目中的矩阵按行和列非递增排序,可以利用有序性优化遍历:

public int countNegatives(int[][] grid) {
    int count = 0;
    int col = grid[0].length;
    
    for (int[] row : grid) {
        // 从右往左找到第一个非负数,后面的元素全为负数
        int j = col - 1;
        while (j >= 0 && row[j] < 0) {
            j--;
        }
        count += (col - j - 1);
    }
    return count;
}

优化点:

  • 时间复杂度从 O(m*n) 降为 O(m+n),适用于大规模数据。
  • 利用矩阵有序性,减少不必要的遍历。

五、总结
知识点关键内容
一维数组初始化静态初始化 {},动态初始化 new int[size]
二维数组结构行数:array.length,列数:array[i].length
遍历方式嵌套循环,外层遍历行,内层遍历当前行的列
常见错误越界、空指针、循环条件错误
优化技巧利用有序性减少遍历次数

88. 合并两个有序数组

阿里云一面

合并两个有序数组

题目描述
给定两个按非递减顺序排列的整数数组 nums1nums2,其中 nums1 的长度为 m + n,前 m 个元素为有效元素,后 n 个元素初始化为0。要求将 nums2 合并到 nums1 中,使得合并后的数组仍保持非递减顺序。最终结果应存储在 nums1 中。

示例

  • 示例1:
    输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
    输出:[1,2,2,3,5,6]

  • 示例2:
    输入:nums1 = [1], m = 1, nums2 = [], n = 0
    输出:[1]

  • 示例3:
    输入:nums1 = [0], m = 0, nums2 = [1], n = 1
    输出:[1]

解题思路
由于需要直接在 nums1 中合并,且 nums1 的末尾有足够的空间,可以采用从后向前合并的方法。这种方法避免了从前向后合并时可能出现的元素覆盖问题。具体步骤如下:

  1. 初始化指针

    • p1:指向 nums1 有效部分的末尾(索引 m-1)。
    • p2:指向 nums2 的末尾(索引 n-1)。
    • p:指向合并后数组的末尾(索引 m+n-1)。
  2. 从后向前合并
    比较 nums1[p1]nums2[p2],将较大的元素放入 nums1[p] 的位置,并将对应指针向前移动。重复此过程直到其中一个数组遍历完成。

  3. 处理剩余元素
    如果 nums2 中仍有元素未合并,说明这些元素是剩余最小的,直接复制到 nums1 的前部。

代码实现

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int p1 = m - 1;
        int p2 = n - 1;
        int p = m + n - 1;

        while (p1 >= 0 && p2 >= 0) {
            if (nums1[p1] > nums2[p2]) {
                nums1[p] = nums1[p1];
                p1--;
            } else {
                nums1[p] = nums2[p2];
                p2--;
            }
            p--;
        }

        // 处理nums2剩余元素
        while (p2 >= 0) {
            nums1[p] = nums2[p2];
            p2--;
            p--;
        }
    }
}

复杂度分析

  • 时间复杂度:O(m + n),每个元素最多被访问一次。
  • 空间复杂度:O(1),无需额外空间。

关键点说明

  • 逆向遍历:避免了正向遍历时的覆盖问题,确保已处理的元素不会被覆盖。
  • 剩余元素处理:只需处理 nums2 的剩余元素,因为 nums1 的剩余元素已处于正确位置。
  • 边界条件:当 m = 0n = 0 时,代码依然能正确处理。

3285. 找到稳定山的下标


1.数组长度获取
在Java中,数组是一个固定大小的对象,其长度通过属性length而不是方法来访问

int[] length = {1,2,3};
int len = height.length;

2.循环边界条件
当我需要遍历一个数组时,通常会使用for循环,但需要注意边界条件避免数组越界异常
对于一个长度为n的数组,有效的索引是从0n-1

for(int i = 1;i < height.length;i++){
//这里i从1开始,遍历到height.length - 1
}

3.列表的初始化与使用

import java.util.ArrayList;
import java.util.List;

List<Integer> list = new ArrayList<>();
list.add(1);

4.返回类型
函数声明返回类型为List<Integer>,意味着我需要返回一个包含整数的列表,在Java中,我可以通过创建一个列表对象,向其中添加所需元素,最后返回列表对象实现

public List<Integer> stableMountains(int[] height,int threshold){
	List<Integer> list = new ArrayList<>();
	for(int i = 1;i<height.length;i++){
		if(height[i-1] == threshold){
			list.add(i);
		}
	}
	return list;
}

最近做的一些leetcode题目记录🫡

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值