算法训练营第二天| 27. 双指针
题目链接https://leetcode.cn/problems/remove-element/视频讲解https://www.bilibili.com/video/BV12A4y1Z7LP自己看到题目的第一想法看到题目要求原地移除数组中所有等于给定值的元素并返回新长度我第一反应是这肯定不能真的“删除”元素因为数组长度是固定的。我想到两种思路暴力解法遇到目标值就把后面所有元素往前挪一位这样时间复杂度是 O(n²)在数据量大的时候肯定不行。双指针法用一个指针遍历数组另一个指针标记有效位置遇到非目标值就放到前面。这样只需要遍历一次时间复杂度 O(n)空间复杂度 O(1)。我决定实现双指针法因为题目明确提示了“Use two pointers!”而且这是更优雅的解法。自己实现过程中遇到哪些困难指针初始化和移动逻辑一开始我搞混了快慢指针的职责。快指针fast应该负责遍历所有元素慢指针slow负责标记下一个有效元素的位置。我最初让两个指针都从0开始但没想清楚什么时候移动慢指针。边界条件处理当数组为空或所有元素都是目标值时需要特别小心。比如nums [3,3], val 3这种情况下应该返回0且数组前0个元素有效。我一开始的代码在空数组时会出现索引错误。原地修改的理解题目说“nums 的其余元素和 nums 的大小并不重要”这意味着我们只需要保证前k个元素正确后面的元素可以不管。但我一开始总想“清理”后面的元素其实没必要。测试用例设计自己测试时发现几个容易出错的用例nums [], val 0空数组nums [1], val 1只有一个元素且为目标值nums [1,2,3,4], val 5没有目标值nums [2,2,2,2], val 2全是目标值今日收获心得双指针的灵活应用这道题是快慢指针同向双指针的经典应用。快指针探索慢指针收集这种模式在很多数组操作问题中都有用比如删除有序数组中的重复项、移动零等。理解题目要求的重要性题目不要求真正删除元素也不要求保持原有顺序虽然我的解法保持了相对顺序这给了我们实现上的灵活性。仔细读题可以避免做无用功。测试驱动开发自己编写多个边界用例并手动模拟指针变化能快速发现逻辑漏洞。比如我通过手动模拟nums [0,1,2,2,3,0,4,2], val 2这个用例才彻底理清了指针移动逻辑。代码简洁性最终实现的代码非常简洁但背后是清晰的思路。好的算法代码应该是思路的直接体现。题目#include iostream #include vector using namespace std; class Solution { public: int removeElement(vectorint nums, int val) { int k 0; for (int i 0; i nums.size(); i) { if (nums[i] ! val) { nums[k] nums[i]; k; } } return k; } }; int main() { Solution sol; vectorint nums1 {3,2,2,3}; int val1 3; int k1 sol.removeElement(nums1, val1); cout k k1 , nums [; for (int i 0; i k1; i) { cout nums1[i]; if (i k1 - 1) cout ,; } cout ] endl; vectorint nums2 {0,1,2,2,3,0,4,2}; int val2 2; int k2 sol.removeElement(nums2, val2); cout k k2 , nums [; for (int i 0; i k2; i) { cout nums2[i]; if (i k2 - 1) cout ,; } cout ] endl; return 0; }
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2518315.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!