数据结构之:数组
创始人
2024-02-03 22:32:47
数组初体验之数组中重复的数字
数组 : 有限个 相同类型的变量 组成的有序集合 int[] arr; int arr[]; // 静态初始化 String[] strArr = {"和平精英","王者荣耀","开心消消乐","欢乐斗地主"}; // 动态初始化 String[] strArr1 = new String[4];

 

数组中重复的数字 https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/

 数组中重复的数字

找出数组中重复的数字。 在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的, 但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数 字。 示例 1: 输入: [2, 3, 1, 0, 2, 5, 3] 输出:2 或 3
解法 1) 集合的解法 set 使用集合存储已遍历过的数据,新数据遍历时,判断是否在集合中存在,如果存在即为重复的
   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。 你不需要考虑数组中超出新长度后面的元素 分析: 需要额外指针 记录新出现的不同元素 需要覆盖的位置

    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;}
双指针应用之移除元素 移除元素 https://leetcode-cn.com/problems/remove-element/

给一个数组 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
    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;}
解法2)直接替换
[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++;}}

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...