面试经典150题刷题——数组/字符串部分

数组部分

1. 合并两个有序的子数组 —— 倒序双指针避免覆盖

88. 合并两个有序数组

        给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

参考题解:. - 力扣(LeetCode)

class Solution {
    
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        /* 
            倒序双指针法:从尾部开始,从而避免覆盖问题 
            m,n 分别表示 nums1 和 nums2 的元素个数
        */  
        int p1 = m - 1; // 指向第一个数组的最后一个元素
        int p2 = n - 1; // 指向第二个元素数组的最后一个元素
        int insert_position = m + n - 1; // 指向要插入的位置
        while (p2 >= 0) { // nums2 还有要合并的元素
            // 如果 p1 < 0,那么走 else 分支,把 nums2 合并到 nums1 中
            if (p1 >= 0 && nums1[p1] > nums2[p2]) {
                nums1[insert_position--] = nums1[p1--]; // 填入 nums1[p1]
            } else {
                nums1[insert_position--] = nums2[p2--]; // 填入 nums2[p1]
            }
        }
    }
}

2. 移除元素 —— 数组末尾元素交换法

27. 移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。

假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:

  • 更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。
  • 返回 k
class Solution {
    public int removeElement(int[] nums, int val) {
        /**
            idea & steps:
                1. 从左往右遍历数组nums,,
                2. 如果与val相同,则与数组最后一个元素交换,
                3. 数组长度 -- 
                4. 注:如果相同了则继续遍历当前元素;(因为当前元素是末尾交换过来的元素,不一定不等于val)
                5. 结束的条件:当前判断的位置与更改后的数组位置相同
         */
        int cur = 0;  // 起始指针
        int rear = nums.length - 1; // 终止指针
        while(cur <= rear) {
            if(nums[cur] == val) {
                nums[cur] = nums[rear];
                rear --;
            }else {
                cur ++;
            }
        }
        return cur;
    }
}

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

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

给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k 。

class Solution {
    public int removeDuplicates(int[] nums) {
        /**
            idea & steps
                1. 利用递增的特性,那么相同元素一定是在挨在一起的
                2. 原地删除
                如果后面的元素与前面的元素相同,则为重复项,不保留
                如果后面的元素与前面的元素不相同,则为重复项,不保留
                用指针 k 指向保留的元素要填入的下标
                // 最后的前k个元素包含唯一元素
         */ 
        int k = 1; // 记录存放元素的位置
        for(int i=1; i < nums.length; i++) {
            if(nums[i] != nums[i-1]) {
                nums[k++] = nums[i];
            }
        }
        return k;
    }
}

4.  删除有序数组中的重复项 Ⅱ - 比较前k位

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

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

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

class Solution {
    public int removeDuplicates(int[] nums) {
        /**
            目标:使得出现超过两次的元素只出现两次,返回删除后数组的新长度
            注:出现1次的元素,仍然进行保留

            ===> 推广到一般情况:将保留2位 修改为 保留k位
            idea & steps: 
                1. 前k个元素直接保存
                2. 后面的元素进行遍历,将其与前k个元素比较,因为是有序的,故只需要与 nums[u-k]进行比较即可
                    只有不同才会进行保留;

            // 保留k位只用把代码中的2修改为k即可,或者封装为一个函数,传入参数k
        */
        int insert_pos = 0; // 记录当前插入的位置
        for(int num : nums) {
            // 注意这里是 insert_pos - 2 而不是 i-2; insert_pos表示当前元素要插入的位置
            // 即可以理解为要插入的元素
            // 如果要插入的元素 与 该位置前面两个元素都相同,则不能插入,继续遍历下一个元素
            if(insert_pos < 2 || nums[insert_pos - 2] != num){
                nums[insert_pos ++] = num;
            } // 前两个元素直接保留
            // printArray(nums);
        }
        return insert_pos;
    }
    // public void printArray(int[] nums) {
    //     for(int num : nums) 
    //         System.out.print(num + " ");
    //     System.out.println();
    // }
}

5. 多数元素-摩尔投票法【正负抵消】

参考题解:. - 力扣(LeetCode)

169. 多数元素

给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值