数组方法汇总

  • 数组和链表类似,都是用双指针,但数组不需要额外的指针,可以使用索引来当作指针。(链表的时候要注意,什么时候是移动的指针,什么时候是改变的节点)
  • 删除有序数组中的重复项
    注意,本题中的数组是有序的,但是有重复项,我们要进行去重,这和链表类似,用快慢指针,快指针不等于慢指针的时候,我们用快指针将慢指针覆盖,然后移动指针。相同的时候移动快指针就好。
    代码中有个需要注意的地方,我们在while循环中,当快慢指针不同的时候,我们需要先移动慢指针,然后再替换,因为这样才能避免慢指针这个地方的元素被覆盖,我们是要去除慢指针后面那个重复元素。
    我们要返回的是数组中不重复元素的个数,所以应该索引+1.

在这里插入图片描述

int removeDuplicates(int[] nums) {
    if (nums.length == 0) {
        return 0;
    }
    int slow = 0, fast = 0;
    while (fast < nums.length) {
        if (nums[fast] != nums[slow]) {
            slow++;
            // 维护 nums[0..slow] 无重复
            nums[slow] = nums[fast];
        }
        fast++;
    }
    // 数组长度为索引 + 1
    return slow + 1;
}

下面是链表的代码(slow.next=fast,就是改变的链表节点连接,而slow = slow.next则是移动的指针,走向下一个节点进行判断)
在这里插入图片描述

ListNode deleteDuplicates(ListNode head) {
    if (head == null) return null;
    ListNode slow = head, fast = head;
    while (fast != null) {
        if (fast.val != slow.val) {
            // nums[slow] = nums[fast];
            slow.next = fast;
            // slow++;
            slow = slow.next;
        }
        // fast++
        fast = fast.next;
    }
    // 断开与后面重复元素的连接
    slow.next = null;
    return head;
}

  • 移除元素
    这个是给定了一个值,让我们移除数组中和这个值相同的元素,其实做法也是快慢指针,和上面题类似,但这里有个细节,我们在判断当这个值和快指针不相等的时候,我们要先替换慢指针的地方,然后再移动慢指针,因为我们是要删除掉与x相等的元素,只要有就删,一个不能留。快指针是用来遍历元素,找到与x不同的值,然后保留在慢指针的位置,慢指针是存储位置的索引。
int removeElement(int[] nums, int val) {
    int fast = 0, slow = 0;
    while (fast < nums.length) {
        if (nums[fast] != val) {
            nums[slow] = nums[fast];
            slow++;
        }
        fast++;
    }
    return slow;
}

  • 移动0
    题中要求将数组的值为0的元素都移动到数组末尾。我们可以先移除数组中的0,然后在数组后面进行补0即可。
    所以我们可以借助上题的删除指定元素的代码,然后删除0,然后再用0补齐数组即可
void moveZeroes(int[] nums) {
    // 去除 nums 中的所有 0,返回不含 0 的数组长度
    int p = removeElement(nums, 0);
    // 将 nums[p..] 的元素赋值为 0
    for (; p < nums.length; p++) {
        nums[p] = 0;
    }
}

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


  • 二分查找
    二分查找我们可以选择左闭右开或者左闭右闭的区间。选择左闭右开,那么左和右肯定不会相等,while(left<right),然后left=mid+1,right=mid
class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length;
        while (left < right) {
            int mid = left + ((right - left) >> 1);
            if (nums[mid] == target)
                return mid;
            else if (nums[mid] < target)
                left = mid + 1;
            else if (nums[mid] > target)
                right = mid;
        }
        return -1;
    }
}
  • 两数之和Ⅱ
    给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length
    数组有序,我们用双指针,为了满足题中索引要求,我们可以使用相向双指针,即left=0,right=nums.length-1。然后来进行判断。注意,两个索引是不相等的,所以我们的while循环中,应该是left<right
int[] twoSum(int[] nums, int target) {
    // 一左一右两个指针相向而行
    int left = 0, right = nums.length - 1;
    while (left < right) {
        int sum = nums[left] + nums[right];
        if (sum == target) {
            // 题目要求的索引是从 1 开始的
            return new int[]{left + 1, right + 1};
        } else if (sum < target) {
            left++; // 让 sum 大一点
        } else if (sum > target) {
            right--; // 让 sum 小一点
        }
    }
    return new int[]{-1, -1};
}

  • 翻转数组
void reverseString(char[] s) {
    // 一左一右两个指针相向而行
    int left = 0, right = s.length - 1;
    while (left < right) {
        // 交换 s[left] 和 s[right]
        char temp = s[left];
        s[left] = s[right];
        s[right] = temp;
        left++;
        right--;
    }
}

  • 回文串判断
    回文串就是正着读和反着读都一样的字符串
    判断字符串是不是回文串
boolean isPalindrome(String s) {
    // 一左一右两个指针相向而行
    int left = 0, right = s.length() - 1;
    while (left < right) {
        if (s.charAt(left) != s.charAt(right)) {
            return false;
        }
        left++;
        right--;
    }
    return true;
}

  • 最长回文子串
    我们可以用双指针来做,但我们要找最长的回文子串,是连续的,我们可以从中心向两端扩散的双指针。
    因为我们是从中心往两边走,找最长的回文子串,如果整个子串都是回文的,那我们走到最左边0的位置,和最右边nums.length-1的位置也符合,这个时候我们的指针还会移动,此时L已经走到了-1,而R已经走到了nums.length,所以我们在截取字符串的时候是截取的substring(l+1,r)。
String longestPalindrome(String s) {
    String res = "";
    for (int i = 0; i < s.length(); i++) {
        // 以 s[i] 为中心的最长回文子串
        String s1 = palindrome(s, i, i);
        // 以 s[i] 和 s[i+1] 为中心的最长回文子串
        String s2 = palindrome(s, i, i + 1);
        // res = longest(res, s1, s2)
        res = res.length() > s1.length() ? res : s1;
        res = res.length() > s2.length() ? res : s2;
    }
    return res;
}
// 在 s 中寻找以 s[l] 和 s[r] 为中心的最长回文串
String palindrome(String s, int l, int r) {
    // 防止索引越界
    while (l >= 0 && r < s.length()
            && s.charAt(l) == s.charAt(r)) {
        // 双指针,向两边展开
        l--; r++;
    }
    // 返回以 s[l] 和 s[r] 为中心的最长回文串
    return s.substring(l + 1, r);
}

  • 合并两个有序数组
    我们不能用新数组,但是如果从前向后遍历的话,会覆盖掉nums1中的元素,我们可以将双指针初始化在数组的尾部,然后从后向前进行合并。
class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        // 两个指针分别初始化在两个数组的最后一个元素(类似拉链两端的锯齿)
        int i = m - 1, j = n - 1;
        // 生成排序的结果(类似拉链的拉锁)
        int p = nums1.length - 1;
        // 从后向前生成结果数组,类似合并两个有序链表的逻辑
        while (i >= 0 && j >= 0) {
            if (nums1[i] > nums2[j]) {
                nums1[p] = nums1[i];
                i--;
            } else {
                nums1[p] = nums2[j];
                j--;
            }
            p--;
        }
        // 可能其中一个数组的指针走到尽头了,而另一个还没走完
        // 因为我们本身就是在往 nums1 中放元素,所以只需考虑 nums2 是否剩元素即可
        while (j >= 0) {
            nums1[p] = nums2[j];
            j--;
            p--;
        }
    }
}

  • 有序数组的平方
    本题其实也是合并数组,只不过把远数字换成平方,我们仍采用双指针,因为这个数组元素的平方的最值,肯定是在数组的两端。我们采用相向双指针,注意,新数组应该从后往前添加,因为我们是从两端开始算的最大值
class Solution {
    public int[] sortedSquares(int[] nums) {
        int n = nums.length;
        // 两个指针分别初始化在正负子数组绝对值最大的元素索引
        int i = 0, j = n - 1;
        // 得到的有序结果是降序的
        int p = n - 1;
        int[] res = new int[n];
        // 执行双指针合并有序数组的逻辑
        while (i <= j) {
            if (Math.abs(nums[i]) > Math.abs(nums[j])) {
                res[p] = nums[i] * nums[i];
                i++;
            } else {
                res[p] = nums[j] * nums[j];
                j--;
            }
            p--;
        }
        return res;
    }
}

  • 有序序列转数组
    一个有序数组,给定abc,对每一个元素计算f(x) = ax2 + bx + c,按照升序返回数组
    所以这道题的关键也是在 nums 的开头和结尾设置 i, j 双指针相向而行,执行合并有序数组的逻辑
class Solution {
    public int[] sortTransformedArray(int[] nums, int a, int b, int c) {
        // 双指针,相向而行,逼近对称轴
        int i = 0, j = nums.length - 1;
        // 如果开口朝上,越靠近对称轴函数值越小
        // 如果开口朝下,越靠近对称轴函数值越大
        int p = a > 0 ? nums.length - 1 : 0;
        int[] res = new int[nums.length];
        // 执行合并两个有序数组的逻辑
        while (i <= j) {
            int v1 = f(nums[i], a, b, c);
            int v2 = f(nums[j], a, b, c);
            if (a > 0) {
                // 如果开口朝上,越靠近对称轴函数值越小
                if (v1 > v2) {
                    res[p--] = v1;
                    i++;
                } else {
                    res[p--] = v2;
                    j--;
                }
            } else {
                // 如果开口朝下,越靠近对称轴函数值越大
                if (v1 > v2) {
                    res[p++] = v2;
                    j--;
                } else {
                    res[p++] = v1;
                    i++;
                }
            }
        }
        return res;
    }

    int f(int x, int a, int b, int c) {
        return a*x*x + b*x + c;
    }
}

  • 区域和检索
    用一维前缀和,前缀和数组比之前数组多一位,并且在presum[0]=0,然后再进行计算,公式为presum[i]=presum[i-1]+nums[i-1],计算两个索引left和right之间的元素和直接可以用presum[right+1]-presum[left]。因为presum[right+1]是计算到了nums中索引从0到right的位置,而presum[left]是计算到了nums中索引从0到left-1的位置,所以二者相减就是left到right之间的元素和。
    在这里插入图片描述
class NumArray {
    // 前缀和数组
    private int[] preSum;

    /* 输入一个数组,构造前缀和 */
    public NumArray(int[] nums) {
        // preSum[0] = 0,便于计算累加和
        preSum = new int[nums.length + 1];
        // 计算 nums 的累加和
        for (int i = 1; i < preSum.length; i++) {
            preSum[i] = preSum[i - 1] + nums[i - 1];
        }
    }
    
    /* 查询闭区间 [left, right] 的累加和 */
    public int sumRange(int left, int right) {
        return preSum[right + 1] - preSum[left];
    }
}

  • 二维前缀和 在这里插入图片描述
    同理,二维前缀和数组我们也多建一行一列,索引从1开始遍历,然后,preSum[i][j] = preSum[i-1][j] + preSum[i][j-1] + matrix[i - 1][j - 1] - preSum[i-1][j-1];
    // 计算子矩阵 [x1, y1, x2, y2] 的元素和
    preSum[x2+1][y2+1] - preSum[x1][y2+1] - preSum[x2+1][y1] + preSum[x1][y1];
class NumMatrix {
    // 定义:preSum[i][j] 记录 matrix 中子矩阵 [0, 0, i-1, j-1] 的元素和
    private int[][] preSum;
    
    public NumMatrix(int[][] matrix) {
        int m = matrix.length, n = matrix[0].length;
        if (m == 0 || n == 0) return;
        // 构造前缀和矩阵
        preSum = new int[m + 1][n + 1];
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                // 计算每个矩阵 [0, 0, i, j] 的元素和
                preSum[i][j] = preSum[i-1][j] + preSum[i][j-1] + matrix[i - 1][j - 1] - preSum[i-1][j-1];
            }
        }
    }
    
    // 计算子矩阵 [x1, y1, x2, y2] 的元素和
    public int sumRegion(int x1, int y1, int x2, int y2) {
        // 目标矩阵之和由四个相邻矩阵运算获得
        return preSum[x2+1][y2+1] - preSum[x1][y2+1] - preSum[x2+1][y1] + preSum[x1][y1];
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/518790.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】--- 探索栈和队列的奥秘

关注小庄 顿顿解馋૮(˶ᵔ ᵕ ᵔ˶)ა &#x1f4a1;个人主页&#xff1a;9ilk &#x1f4a1;专栏&#xff1a;数据结构之旅 上回我们学习了顺序表和链表&#xff0c;今天博主来讲解两个新的数据结构 — 栈和队列 &#xff0c; 请放心食用 文章目录 &#x1f3e0; 栈&#x1…

红黑树内部结点数量分析

红黑树内部结点数量分析 一、红黑树的性质二、黑高与内部结点数量2.1最大内部结点数量2.2最小内部结点数量 三、伪代码实现四、C语言代码实现五、结论 红黑树是一种自平衡的二叉搜索树&#xff0c;它通过一系列复杂的性质和操作来维持平衡&#xff0c;从而确保各种动态集合操作…

来get属于你的达坦科技令人心动的offer吧!

我们是谁 达坦科技始终致力于打造高性能Al Cloud 基础设施平台DatenLord&#xff0c;积极推动AI应用的落地。DatenLord通过软硬件深度融合的方式&#xff0c;提供高性能存储和高性能网络。为AI 应用提供弹性、便利、经济的基础设施服务&#xff0c;以此满足不同行业客户对AICl…

【Unity每日一记】如何让Sprite精灵图集的背景图层变成透明,方便切割

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

CSS基础:4种简单选择器的详解

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端的程序媛。大专生&#xff0c;2年时间从1800到月入过万&#xff0c;工作5年买房。 分享成长心得。 261篇原创内容-公众号 后台回复“前端工具”可获取开发工具&#xff0c;持续更新中 后台回复“前端基础…

Axure案例分享—垂直手风琴(附下载地址)

今天分享的案例是Axure8(兼容9和10)制作的垂直手风琴 一、功能介绍 折叠或展开多个面板内容&#xff0c;默认为展开一项内容&#xff0c;点击任一收起的选项&#xff0c;展开面板&#xff0c;其他面板收起二、制作过程 原型是由矩形组件以及动态面板构成&#xff0c; 拖入一…

面向C++程序员的Rust教程(二)

先序文章请看&#xff1a; 面向C程序员的Rust教程&#xff08;一&#xff09; 所有权与移动语义 要说Rust语言跟其他语言最大的区别&#xff0c;那笔者觉得非数这个所有权和移动语义莫属。 深浅复制 对于绝大多数语言来说&#xff0c;变量/对象之间的赋值通常都是复制语义。…

python标准数据类型--元组常用方法

在Python中&#xff0c;元组&#xff08;Tuple&#xff09;是一种不可变的有序集合&#xff0c;它与列表类似&#xff0c;但是元组中的元素不能被修改。元组通常用于存储不可变的数据集合&#xff0c;例如一组常量或者一组固定的值。本篇博客将介绍一些Python中元组的常用方法&…

软考高级架构师:人工智能芯片概念和例题

一、AI 讲解 人工智能芯片是专门设计来处理与人工智能&#xff08;AI&#xff09;相关的任务的集成电路。这些芯片针对AI应用的高计算需求进行了优化&#xff0c;以提升处理速度和效率&#xff0c;同时降低能耗。它们在AI领域&#xff0c;如深度学习、机器学习和数据分析中发挥…

python爬虫获取豆瓣前top250的标题(简单)

今天是简略的一篇&#xff0c;简单小实验 import requests from bs4 import BeautifulSoup# 模拟浏览器的构成&#xff08;请求头&#xff09; headers {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Ch…

10 款最佳 Mac 数据恢复软件,在为时已晚之前值得尝试

查看 10 年适用于 Mac 的 2024 款最佳免费数据恢复软件&#xff0c;可在大多数在线搜索中找到。精选列表将帮助您做出明智的决定并节省您的时间和精力。 10 款最佳 Mac 数据恢复软件 很明显&#xff0c;您此后将面临数据丢失事件。理所当然地&#xff0c;您期待一款可靠、与您…

中文大模型隐私保护哪家强?InternLM 与 Baichuan2 胜出!

引言&#xff1a;中文大模型隐私保护能力探索 本文研究了大语言模型&#xff08;LLMs&#xff09;对隐私和安全的影响&#xff0c;采用了三层渐进框架对语言系统的隐私进行评估。主要目标是全面评估LLMs对私人信息的敏感性&#xff0c;并检查其在识别、管理和保护敏感数据方面…

微信小程序短链接工具推荐

现在微信小程序大行其道&#xff0c;但工作中大部分人选择了短链接的方式来推广微信小程序&#xff0c;那么微信小程序短链接工具哪个好?今天就分享一篇从网上看到的关于《微信小程序短链接工具推荐》文&#xff0c;作者是souki&#xff0c;一起来看看吧! 一、缩链 1、生成方…

【智能算法】阿基米德优化算法(AOA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2020年&#xff0c;Hashim等人受到阿基米德定律启发&#xff0c;提出了阿基米德优化算法&#xff08;Archimedes Optimization Algorithm&#xff0c;AOA&#xff09;。 2.算法原理 2.1算法思想 …

python导入本地当前目录下的文件和父目录下的文件

今天我想要导入本地当前目录下的文件和父目录下的文件&#xff0c;网上查了很多教程&#xff0c;但还都是报错&#xff0c;最后几经尝试&#xff0c;终于成功解决了这一问题&#xff0c;在这里详细记录一下过程&#xff0c;同时也希望能够对大家有所帮助~~~:&#xff09; 导入…

Python人工智能应用---中文分词词频统计

目录 1.中文分词 2.循环分别处理列表 &#xff08;1&#xff09;分析 &#xff08;2&#xff09;代码解决 3.词袋模型的构建 &#xff08;1&#xff09;分析需求 &#xff08;2&#xff09;处理分析 1.先实现字符串的连接 2.字符串放到新的列表里面 4.提取高频词语 &…

vivado 向 SVF 目标添加器件

向 SVF 目标添加器件 创建 SVF 目标后 &#xff0c; 可向其中添加器件以定义 SVF JTAG 器件链配置。 SVF JTAG 器件链配置应与目标硬件链相匹配 &#xff0c; 以 确保能正确执行 SVF 文件。 使用 Vivado IDE 单击“ ”按钮以向 SVF 链添加赛灵思器件或非赛灵思器件。…

程序·人生

诡异之极 2024.03.12 清新环境&#xff08;股票代码002573&#xff09;委托卖出 20000股&#xff0c;委托价4.58&#xff0c;当日最高价4.57 2024.03.11 清新环境&#xff08;股票代码002573&#xff09;委托卖出 20000股&#xff0c;委托价4.55&#xff0c;当日最高价4.54 …

【Python系列】读取 Excel 第一列数据并赋值到指定列

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

windwos安全加固

一、账号管理 按用户类型分配账号 目的&#xff1a;根据系统要求&#xff0c;设定不同账户和组&#xff0c;管理员、数据库 sa、审计用户、来宾用户等 实施方法&#xff1a; 打开本地用户和计算机管理器 ​ 1.打开运行&#xff0c;输入lusrmgr.msc 2.根据用户要求将账户加入…