轻松掌握数组操作技巧,LeetCode刷题记录【1】助你轻松搞定有序数组合并、删除重复项
2023-05-18 20:36:25
掌握 LeetCode 算法:解决数组操作的常见难题
作为软件工程师,算法和数据结构的熟练运用是必不可少的技能。而 LeetCode 作为算法练习的领头羊,更是备受程序员推崇,是面试备战的必备神器。
在本文中,我们将深入探讨 LeetCode 刷题记录中的三个经典数组操作问题:有序数组合并、移除数组指定元素和删除有序数组中重复项。通过逐一解剖这些问题,我们将在轻松掌握其解法的同时,提升我们的数组操作技巧,为编程面试做好充分准备。
有序数组合并
设想这样的场景:你手头有两个已经排好序的数组,nums1 和 nums2。现在你的任务是将这两个数组合并为一个新的有序数组。
解法一:暴力法
暴力法是一种直观的解法,它逐个比较 nums1 和 nums2 中的元素,将较小的元素加入到新数组中。这种方法虽然简单易懂,但效率较低,尤其是当数组规模较大时。
void merge(int* nums1, int m, int* nums2, int n) {
int i = 0, j = 0, k = 0;
while (i < m && j < n) {
if (nums1[i] < nums2[j]) {
nums1[k] = nums1[i];
i++;
} else {
nums1[k] = nums2[j];
j++;
}
k++;
}
while (i < m) {
nums1[k] = nums1[i];
i++;
k++;
}
while (j < n) {
nums1[k] = nums2[j];
j++;
k++;
}
}
解法二:双指针法
双指针法是一种更为高效的解法。它使用两个指针 i 和 j 分别遍历 nums1 和 nums2,将较小的元素加入到新数组中。当一个数组遍历完毕后,将剩余的另一个数组的元素全部加入到新数组中。
void merge(int* nums1, int m, int* nums2, int n) {
int i = m - 1, j = n - 1, k = m + n - 1;
while (i >= 0 && j >= 0) {
if (nums1[i] > nums2[j]) {
nums1[k] = nums1[i];
i--;
} else {
nums1[k] = nums2[j];
j--;
}
k--;
}
while (j >= 0) {
nums1[k] = nums2[j];
j--;
k--;
}
}
移除数组指定元素
现在,我们有一个数组 nums 和一个元素 val。我们的目标是移除数组中所有值为 val 的元素,并返回移除后的数组长度。
解法一:双指针法
双指针法可以再次派上用场。它使用两个指针 i 和 j 分别遍历 nums。当 j 指向值为 val 的元素时,我们跳过该元素,继续遍历。当 j 指向非 val 元素时,我们将该元素移动到位置 i,并更新 i 指针。
int removeElement(int* nums, int n, int val) {
int i = 0, j = 0;
while (j < n) {
if (nums[j] != val) {
nums[i] = nums[j];
i++;
}
j++;
}
return i;
}
解法二:原地修改法
原地修改法是一种更为简洁的解法。它使用一个指针 k 来覆盖数组中的非 val 元素。当 nums[i] 不等于 val 时,我们将 nums[i] 移动到位置 k 并更新 k。
int removeElement(int* nums, int n, int val) {
int k = 0;
for (int i = 0; i < n; i++) {
if (nums[i] != val) {
nums[k] = nums[i];
k++;
}
}
return k;
}
删除有序数组中重复项
最后,我们有一个有序数组 nums。我们的任务是删除所有重复元素,并返回不重复元素的数组长度。
解法一:双指针法
双指针法又一次大显身手。它使用两个指针 i 和 j 分别遍历 nums。当 nums[i] 等于 nums[j] 时,我们跳过重复元素,继续遍历。当 nums[i] 不等于 nums[j] 时,我们将 nums[j] 移动到位置 i + 1 并更新 i 指针。
int removeDuplicates(int* nums, int n) {
if (n == 0) {
return 0;
}
int i = 0, j = 1;
while (j < n) {
if (nums[j] != nums[i]) {
nums[i + 1] = nums[j];
i++;
}
j++;
}
return i + 1;
}
解法二:原地修改法
原地修改法再次出马。它使用一个指针 k 来覆盖数组中的不重复元素。当 nums[i] 不等于 nums[i - 1] 时,我们将 nums[i] 移动到位置 k 并更新 k。
int removeDuplicates(int* nums, int n) {
int k = 0;
for (int i = 0; i < n; i++) {
if (i == 0 || nums[i] != nums[i - 1]) {
nums[k] = nums[i];
k++;
}
}
return k;
}
常见问题解答
-
为什么双指针法在这些问题中如此常用?
双指针法是一种高效的技巧,因为它减少了数组的遍历次数,降低了时间复杂度。 -
原地修改法和双指针法有什么区别?
原地修改法不会创建新数组,而是覆盖原数组中的元素。双指针法则会创建一个新数组来存储不重复的元素。 -
何时选择使用暴力法而不是双指针法或原地修改法?
当数组规模较小时,暴力法可能更简单、更直观。然而,对于大型数组,双指针法或原地修改法在效率方面更胜一筹。 -
这些算法的时间复杂度是多少?
有序数组合并、移除数组指定元素和删除有序数组中重复项的时间复杂度都是 O(n),其中 n 是数组的长度。 -
在编程面试中如何应对数组操作问题?
首先理解问题,然后选择合适的算法。清晰地解释你的解决方案,并注意时间和空间复杂度。
结论
通过剖析这些 LeetCode 难题,我们掌握了解决数组操作问题的基本技巧。双指针法和原地修改法是两大法宝,可以大幅提升我们的算法效率。在编程面试中,熟练运用这些算法至关重要。通过坚持练习和不断探索,相信我们都能成为算法解题高手,为面试成功做好万全准备。