数组 : 有限个 相同类型的变量 组成的有序集合 int[] arr; int arr[]; // 静态初始化 String[] strArr = {"和平精英","王者荣耀","开心消消乐","欢乐斗地主"}; // 动态初始化 String[] strArr1 = new String[4];

解法 1) 集合的解法 set 使用集合存储已遍历过的数据,新数据遍历时,判断是否在集合中存在,如果存在即为重复的数组中重复的数字
找出数组中重复的数字。 在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的, 但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数 字。 示例 1: 输入: [2, 3, 1, 0, 2, 5, 3] 输出:2 或 3
public static int findRepeatNumber(int[] nums) {Set set = new HashSet<>();
// 遍历数组 iter快捷键for (int num : nums) {if (set.contains(num)) {System.out.println("发现重复元素" + num);return num;}System.out.println("添加元素" + num);set.add(num);}return -1;}
2) 先排序后查找
排序后重复元素相邻 [2, 3, 1, 0, 2, 5, 3] [0, 1, 2, 2, 3, 3, 5]
public static int findRepeatNumber1(int[] nums) {
// 操作数组的工具类 进行排序System.out.println(Arrays.toString(nums));Arrays.sort(nums);System.out.println(Arrays.toString(nums));
// itar快捷键 通过判断相邻元素是否相等 返回是否重复for (int i = 1; i < nums.length; i++) {if (nums[i] == nums[i - 1]) {return nums[i];}}return -1;}
3) 临时数组
因为长度为 n 的数组 nums 里的所有数字都在 0~n-1 所以 临时数组中的索引 对应所有可能出现的数字 遍历时 将出现数字 对应到临时数组的索引位置 更改元素值 0 - 1 当临时数组的元素 不为0时 说明此索引位置 已经出现过元素了 [2, 3, 1, 0, 2, 5, 3] [0, 0, 0, 0, 0, 0, 0] 0 1 2 3 4 5 6 [0, 0, 1, 0, 0, 0, 0] [0, 0, 1, 1, 0, 0, 0] [0, 1, 1, 1, 0, 0, 0] [1, 1, 1, 1, 0, 0, 0]
public static int findRepeatNumber2(int[] nums) {System.out.println(Arrays.toString(nums));
// 临时数组 所有元素默认是0int[] tmp = new int[nums.length];System.out.println(Arrays.toString(tmp));for (int i = 0; i < nums.length; i++) {int num = nums[i];
// 如果已经复制 代表重复出现if (tmp[num] != 0) {return num;}
// 找到临时数组的索引位置 赋值为1tmp[num] = 1;System.out.println(Arrays.toString(tmp));}return -1;}
4) 交换位置查找
[2, 3, 1, 0, 2, 5, 3] 0 1 2 3 4 5 6 [0, 1, 2, 3, 2, 5, 3] 0 1 2 3 4 5 6 [2, 3, 1, 0, 2, 5, 3] 遍历数组的过程中 希望当前位置 和 出现元素正好匹配上 先判断 是否匹配 如果不匹配 进行交换 并且看需要交换的位置 是否存在期望元素 如果可以交换 交换之后 继续遍历当前位置 如果不可交换 即为重复元素 0 1 2 3 4 5 6 遍历2 交换2和1 [1, 3, 2, 0, 2, 5, 3] 遍历1 交换1和3 [3, 1, 2, 0, 2, 5, 3] 遍历3 交换3和0 [0, 1, 2, 3, 2, 5, 3] 遍历0 不交换 遍历1 不交换 遍历2 不交换 遍历3 不交换 遍历2 已经出现期望元素 是重复元素
public static int findRepeatNumber3(int[] nums) {System.out.println(Arrays.toString(nums));
// [2, 3, 1, 0, 2, 5, 3]for (int i = 0; i < nums.length; i++) {
// 如果索引正好等于元素本身 是期望的结果 跳过if (nums[i] == i) continue;
// i = 0int num = nums[i]; // 2
// 如果要交换的位置 已经有期望值 说明重复if (nums[num] == num) {System.out.println("当前索引为" + num + "的位置 已经有" + num +"值,重复了");return num;}int tmp = nums[num]; // 1nums[num] = num;nums[i] = tmp;
// [1, 3, 2, 0, 2, 5, 3]
// 交换仍需遍历当前位置的值 所以抵消i++i--;System.out.println(Arrays.toString(nums));}return -1;}
数组初体验之数组中消失的数字
数组中消失的数字
https://leetcode-cn.com/problems/fifind-all-numbers-disappeared-in-an-array/
找到所有数组中消失的数字 给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一 些只出现一次。 找到所有在 [1, n] 范围之间没有出现在数组中的数字。 您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算 在额外空间内。 示例: 输入: [4,3,2,7,8,2,3,1] 输出: [5,6] 解法: 1)使用容器存储已出现的数字 [4,3,2,7,8,2,3,1] 额外容器 [4,3,2,7,8,1] 1-8(数组的长度) [5,6] set list map 不重复无序 适用set 可能重复且有序 适用list 映射关系 <元素,出现的次数> map
public static List findDisappearedNumbers(int[] nums) {List result = new ArrayList<>();
// 使用set 存储已出现的数字Set set = new HashSet<>();for (int num : nums) {set.add(num);}
// 从1-n开始遍历for (int i = 1; i <= nums.length; i++) {if (!set.contains(i)) {result.add(i);}}return result;}
2)不使用额外的空间?
[1,2,4,5,1] 1-5 [3] [1,2,4,5,1] 0 1 2 3 4 1 2 3 4 5 能不能利用 索引 来记录已出现的数字? 元素 索引i 第i位的值进行变化 说明 1 0 [-1,2,4,5,1] 1变为-1 2 1 [-1,-2,4,5,1] 2变为-2 4 3 [-1,-2,4,-5,1] 5变为-5 5 4 [-1,-2,4,-5,-1] 倒数的1变为-1 1 0 [-1,-2,4,-5,-1] 剩余还是正数的元素 索引对应的值从未出现过
public static List findDisappearedNumbers1(int[] nums) {List result = new ArrayList<>();
// 元素对应的索引 将指定位置元素 置为负数for (int i = 0; i < nums.length; i++) {int num = Math.abs(nums[i]);int index = num - 1;
// 将对应索引位置的值置为负数 前提是这个数是整数if (nums[index] > 0) {nums[index] = -nums[index];System.out.println("索引" + index + " " + Arrays.toString(nums));}}for (int i = 0; i < nums.length; i++) {if (nums[i] > 0) {result.add(i + 1);System.out.println(nums[i] + "元素仍为正数,找到" + (i + 1));}}return result;}
数组初体验之多数元素
多数元素
https://leetcode-cn.com/problems/majority-element/
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的 元素。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入: [3,2,3] 输出: 3 示例 2: 输入: [2,2,1,1,1,2,2] 输出: 2 解法分析: 1)使用map记录 <元素,出现次数> 如果次数超过 n/2 即为要查找的元素 数组 [3,2,3] map <3,1> <2,1> <3,2> 判断条件 2 > 3/2 = 1
public static int majorityElement(int[] nums) {
// map 记录元素出现个数Map map = new HashMap<>();
// 统计 多数元素 满足结果int halfLen = nums.length / 2;for (int i = 0; i < nums.length; i++) {int num = nums[i];
// 元素次数 初始化是1int count = 1;if (map.containsKey(num)) {count = map.get(num);count++;}
// 判断是否是多数元素if (count > halfLen) {return num;}System.out.println(num + "元素,存储次数为" + count);map.put(num, count);}return -1;}
2)排序后取中间元素
[3,2,3] [2,3,3] [2,2,1,1,1,2,2] [1,1,1,2,2,2,2] [1,1,1,2] [1,2,2,2]
public static int majorityElement1(int[] nums) {Arrays.sort(nums);System.out.println(Arrays.toString(nums));int halfLen = nums.length / 2;return nums[halfLen];}
3)投票算法
将元素当做候选人,如果新元素和候选人相同,次数+1, 不同次数-1(代表抵消) 如果次数=0,候选人更新 [2,2,1,1,1,2,2] 元素 次数 候选人 2 1 2 2 2 1 1 1 0 1 1 1 2 0 2 1 2 本质上 多数元素出现的次数 一定大于其他所有元素出现次数的总和 所以候选人的次数经过抵消后 最终剩余的一定是“多数元素”
public static int majorityElement2(int[] nums) {
// 候选人int candidate = -1;
// 出现次数int count = 0;for (int i = 0; i < nums.length; i++) {
// 如果出现次数为0 重置候选人if (count == 0) {candidate = nums[i];}
// 根据新元素是否等于候选人 进行次数的加减操作if (candidate == nums[i]) {count++;} else {count--;}System.out.println("元素" + nums[i] + ",次数" + count+ ",候选人" + candidate);}return candidate;}
稀疏数组的定义和转化
稀疏数组
二维数组 : 每个元素都是一维数组 int[][] arr = new int[10][10] 0 1 2 3 4 5 6 7 8 9 0 [0,0,0,0,0,0,0,0,0,0] 1 [0,0,1,0,0,0,0,0,0,0] 2 [0,0,2,0,0,0,0,0,0,0] 3 [0,2,0,0,0,0,0,0,0,0] 4 [0,0,0,0,0,0,0,0,0,0] 5 [0,0,0,0,0,0,0,0,0,0] 6 [0,0,0,0,0,0,0,0,0,0] 7 [0,0,0,0,0,0,0,0,0,0] 8 [0,0,0,0,0,0,0,0,0,0] 9 [0,0,0,0,0,0,0,0,0,0] 稀疏数组 保存原始的行数和列数 保存非零元素的位置 行 列 元素值 10 10 3 1 2 1 3 1 2 2 2 2 用 (n+1)*3列的数组 压缩,n代表非零元素的个数 第一行 存储总行数 总列数 和 非零元素的个数 接下来每一行 存储 元素的行数 列数 和 自身元素值
// 把普通数组 转化为 稀疏数组public static int[][] toSparse(int[][] arr) {
// (n+1)*3列的数组 初始化
// 需要先求 非零元素的个数int count = 0;for (int i = 0; i < arr.length; i++) {for (int j = 0; j < arr.length; j++) {if (arr[i][j] != 0) {count++;}}}int[][] result = new int[count + 1][3];result[0][0] = arr.length;result[0][1] = arr[0].length;result[0][2] = count;
// 遍历数组 找到所有非零元素 存储到结果中int index = 0;for (int i = 0; i < arr.length; i++) {for (int j = 0; j < arr.length; j++) {if (arr[i][j] != 0) {index++;result[index][0] = i;result[index][1] = j;result[index][2] = arr[i][j];}}}return result;}
经典算法思想之双指针

索引i 是一个指针 一个引用 for(int i=0;i删除排序数组中的重复项 https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ 给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后 数组的新长度。 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。示例 1: 给定数组 nums = [1,1,2], 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 你不需要考虑数组中超出新长度后面的元素。 示例 2: 给定 nums = [0,0,1,1,1,2,2,3,3,4], 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 你不需要考虑数组中超出新长度后面的元素 分析: 需要额外指针 记录新出现的不同元素 需要覆盖的位置
双指针应用之移除元素 移除元素 https://leetcode-cn.com/problems/remove-element/public static int removeDuplicates(int[] nums) {if (nums.length == 0) return 0; // 记录要比较的元素位置int index = 0;for (int i = 1; i < nums.length; i++) { // 如果不同 进行覆盖if (nums[i] != nums[index]) {index++;nums[index] = nums[i];System.out.println("覆盖第" + index + "位置的元素为" + nums[i]);}} // 新数组的长度 = 最大索引+1return index + 1;}给一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数 组的新长度。 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。 示例 2: 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。 注意这五个元素可为任意顺序。 你不需要考虑数组中超出新长度后面的元素。 分析: 解法1) 双指针覆盖 [3,2,1,3] val = 3 使用额外指针 记录要覆盖的索引位置 索引 3 0 [3,2,1,3] 2 1 [2,2,1,3] 1 2 [2,1,1,3] 3 [0,1,2,2,3,0,4,2] val = 2 索引初始值是0 元素 索引 数组 0 1 [0,1,2,2,3,0,4,2] 1 2 [0,1,2,2,3,0,4,2] 2 2 3 3 [0,1,3,2,3,0,4,2] 0 4 [0,1,3,0,3,0,4,2] 4 5 [0,1,3,0,4,0,4,2] 2解法2)直接替换public static int removeElement(int[] nums, int val) { // 记录要覆盖的索引位置int index = 0;for (int i = 0; i < nums.length; i++) {if (nums[i] != val) { // 覆盖的是当前位置nums[index] = nums[i];System.out.println("将" + nums[i] + "覆盖到" + index + "位置上");index++;}} // 新数组的长度大小return index;}[0,1,2,2,3,0,4,2] val=2 [0,1,2,2,3,0,4|,2] len=7 [0,1,4,2,3,0|,2,2] len=6 [0,1,4,0,3|,2,2,2] len=5 index=0 len=8 判断当前值 是否需要被删除 如果需要 进行替换 替换最后一个位置的元素 nums[index] = nums[len-1] len--; index--; // 替换回来的值 仍要进行判断 index++ 当index >= len 循环结束public static int removeElement1(int[] nums, int val) {int index = 0; // 记录有效元素的个数int len = nums.length;while (true) {if (index >= len) return len;if (nums[index] == val) {nums[index] = nums[len - 1];nums[len - 1] = val;System.out.println("替换位置" + index + "和" + (len - 1) + "的元素");System.out.println(Arrays.toString(nums));len--;index--;}index++;}}
上一篇:以我的话结尾的成语