【每日三题】删除有序数组重复项,通用解法

202 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,点击查看活动详情 >>


每日三刷,剑指千题

计划简介:

  • 每日三题,以中等题为主,简单题为辅进行搭配。保证质量题1道,数量题3道。
  • 每日早通勤在LeetCode手机端选题,思考思路,没答案的直接看题解。
  • 每日中午进行编码,时间控制在一小时之内。
  • 下班前半小时进行整理总结,并发布到掘金每日更文活动。

说明:

  • 基于以前的刷题基础,本次计划以中等题为主,大部分中等题都可以拆分为多个简单题,所以数量保证3,质量保证一道中等题即可。
  • 刷题顺序按照先刷链表、二叉树、栈、堆、队列等基本数据结构,再刷递归、二分法、排序、双指针等基础算法,最后是动态规划、贪心、回溯、搜索等复杂算法。
  • 刷题过程中整理相似题型,刷题模板。
  • 目前进度 165/1000

今日题型

双指针

[541]反转字符串 II

给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。

  • 如果剩余字符少于 k 个,则将剩余字符全部反转。
  • 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

示例 1:

输入:s = "abcdefg", k = 2
输出:"bacdfeg"

解析

局部双指针,再将结果合并。

Code

class Solution {
        public String reverseStr(String s, int k) {
            char[] chars = s.toCharArray();
            int count = s.length() / (2 * k) + 1;
            int times = 0;
            while (times < count) {
                int head = times * 2 * k;
                int tail = Math.min(times * 2 * k + k - 1, s.length() - 1);
                while (head < tail) {
                    char c = chars[head];
                    chars[head] = chars[tail];
                    chars[tail] = c;
                    head++;
                    tail--;
                }
                times++;
            }
            return String.copyValueOf(chars);
​
        }
    }

[剑指 Offer 57]和为s的两个数字

输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[2,7] 或者 [7,2]

解析

典型双指针题

Code

class Solution {
        public int[] twoSum(int[] nums, int target) {
            int head = 0, tail = nums.length - 1;
            while (head < tail) {
                if (nums[head] + nums[tail] == target) {
                    return new int[]{nums[head], nums[tail]};
                } else if (nums[head] + nums[tail] > target) {
                    tail--;
                } else {
                    head++;
                }
            }
            return new int[2];
        }
    }

[80]删除有序数组中的重复项 II

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

示例 1:

输入:nums = [1,1,1,2,2,3]
输出:5, nums = [1,1,2,2,3]
解释:函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。 不需要考虑数组中超出新长度后面的元素。

解析

参考【宫水三叶的通用解法

但我觉得用 for 循环写 不太好理解,对我个人来说吧,我觉得用 while 更体现双指针。

Code

    class Solution {
        public int removeDuplicates(int[] nums) {
            int head = 0, tail = 0;
            while (head < nums.length) {
                if (2 > tail || nums[tail - 2] != nums[head]) {
                    nums[tail++] = nums[head];
                }
                head++;
            }
            return tail;
        }
    }

\