两个指针实现数组遍历_两遍两遍指针有什么区别

两个指针实现数组遍历

The two-pointer technique is commonly used to optimize solutions to string, array, or linked-list coding problems. In naive solutions, searching for a set of elements in one of those data structures, in the worst-case, can have a polynomial-time complexity such as O(n²), O(n³), O(n⁴), etc. However, using the two-pointer technique on sorted data, the time complexity is reduced to O(n). On the other hand, although the two-pass approach is also used to solve string, array, or linked-list coding problems, it might not necessarily be an optimal solution.

两指针技术通常用于优化针对字符串,数组或链表编码问题的解决方案。 在朴素的解决方案中,在最坏的情况下,在其中一个数据结构中搜索一组元素会具有多项式时间复杂度,例如O(n²),O(n³),O(n⁴)等。 ,对分类数据使用两指针技术,时间复杂度降低为O(n)。 另一方面,尽管两次遍历方法也用于解决字符串,数组或链表编码问题,但它不一定是最佳解决方案。

什么是两次通过方法? (What is the two-pass approach?)

The two-pass approach uses two independent loops to solve a problem; the first loop used extracts some information about the state of the input, and the second loop uses that information to solve the problem.

两遍方法使用两个独立的循环来解决问题。 第一个循环使用有关输入状态的信息,第二个循环使用该信息解决问题。

For example, Sort Colors is a coding problem offered on Leetcode. The crux of the problem is to sort all the objects in-place such that the same colors (numbers) are adjacent, with numbers sorted from 0 to 2.

例如,“排序颜色”是Leetcode上提供的编码问题。 问题的关键是就地对所有对象进行排序,以使相同的颜色(数字)相邻,数字从0到2进行排序。

Input: [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]

Although the two-pass approach allows us to solve the problem in the worst-case time of O(n), the space complexity is also O(n). O(n) is due to the need to store the number of occurrences for each number/color in a data structure (I used an array, but the same would hold for a hash map, because it still takes up multiple slots in memory).

尽管两次通过方法使我们能够在O(n)的最坏情况下解决问题,但空间复杂度也是O(n)。 O(n)是由于需要在数据结构中存储每个数字/颜色的出现次数(我使用了一个数组,但是对于哈希映射也是如此,因为它仍然占用内存中的多个插槽)

/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var sortColors = function(nums) {
const colorMap = [0, 0, 0]
// record the number of occurences for each number/color
for (let i of nums) {
colorMap[i] += 1
}
let start = 0
for (let key = 0; key < 3; key++) {
// use colorMap to change nums in-place
}
}

However, there are instances where using the two-pass approach produces an optimal space complexity, for example, in the Leetcode problem Move Zeros. In this problem, all zeros in the input must be at the end of the array, and it must happen in-place.

但是,在某些情况下,使用两次通过方法会产生最佳的空间复杂度,例如在Leetcode问题“ Move Zeros”中。 在此问题中,输入中的所有零必须位于数组的末尾,并且必须就地发生。

Input: [0,1,0,3,12]
Output: [1,3,12,0,0]

In this case, the first loop in the two-pass approach counts the number of zero occurrences in the input, and the data is stored as an integer variable. Therefore, the space complexity is O(1).

在这种情况下,两次遍历方法中的第一个循环对输入中出现零的次数进行计数,并将数据存储为整数变量。 因此,空间复杂度为O(1)。

/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var moveZeroes = function(nums) {
let count = 0
for (x of nums) {
count += x == 0 ? 1 : 0
}
let ptr = 0
let found = 0
while (ptr < nums.length && found != count) {
//solve using the count
}
};

什么是两点方法? (What’s the two-pointer approach?)

The two-pointer approach uses two variables to trace over each element in a data structure. However, unlike the two-pass approach, the two-pointer technique provides us with a bit of flexibility to look-ahead, look-behind, and compare different windows of data. It analyzes the state of the input and transforms it with each iteration of the loop.

两指针方法使用两个变量来跟踪数据结构中的每个元素。 但是,与两次遍历方法不同,两次指针技术为我们提供了一些灵活性,可以提前,后退和比较不同的数据窗口。 它分析输入的状态,并在每次循环迭代时对其进行转换。

There are two types of two-pointer techniques.

两点技术有两种。

Equi-directional: Both pointers start from the beginning, but one is a fast-running pointer, whereas the second pointer is a slow-running pointer. The slow-running pointer is updated when some condition is met. This two-pointer technique can help us analyze different windows of the input, explore and compare subsets of the input, or detecting cycles in an input.

等向的:两个指针都从头开始,但是一个是快速运行的指针,而第二个指针是运行慢的指针。 满足某些条件时,将更新慢速运行指针。 这种两指针技术可以帮助我们分析输入的不同窗口,探索和比较输入的子集或检测输入中的周期。

Image for post
AlgoDaily in 使用两指针技术Using the Two Pointer Technique AlgoDaily中获取的图像

Here’s is an example solution of Sort Colors, using the Equi-directional approach. Notice, the slow pointer is only updated once the fast pointer has searched the entire array. There’s a lot more to this solution than this sample I’ve provided, but this is the basic idea.

这是使用等方向方法进行颜色排序的示例解决方案。 注意,仅当快速指针搜索了整个数组后,才更新慢速指针。 除了我提供的这个示例之外,此解决方案还有很多其他内容,但这是基本思想。

/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var sortColors = function(nums) {
let slow_pointer = 0 // slow pointer
let fast_pointer = n+1 // fast pointer
// other variables ...
while (slow_pointer < nums.length) {
/// do a lot of work here .....fast_pointer ++; // updated on every iterationif (fast_pointer >= nums.length) {
slow_pointer = nxt
nxt = slow_pointer + 1
fast_pointer = nxt
// ... other variables
}
}
};

Opposite Directional: Two pointers starting from different ends of the input. They move towards each other until some condition is met. This two-pointer technique can help us move data efficiently within the input, compare different ends of the input, and it can also detect cycles.

相反方向:从输入的不同末端开始的两个指针。 他们彼此靠近直到满足某些条件。 这种两指针技术可以帮助我们在输入中有效地移动数据,比较输入的不同端,还可以检测周期。

Image for post
AlgoDaily in 使用两指针技术Using the Two Pointer Technique AlgoDaily中获取的图像

In this sample solution of Move Zeros, both pointers are moving towards each other, given a particular condition. In the opposite directional approach, there isn’t necessarily a “fast pointer” or “slow pointer,” the idea is that both pointers are move at relatively the same speed until they overlap.

在移动零点的此示例解决方案中,给定特定条件,两个指针都朝着彼此移动。 在相反的方向方法中,不一定有“快速指针”或“慢速指针”,其思想是两个指针以相对相同的速度移动,直到它们重叠。

/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var moveZeroes = function(nums) {
...
let pointerA = 0
let pointerB = nums.length - 1
while (pointerA != pointerB) {
if (nums[pointerA] == 0) {
// ... do something then, update pointer
pointerB--;
} else {
pointerA++
}
}
}

那么你怎么知道什么时候使用什么呢? (So how do you know when to use what?)

Firstly, you can’t think of an optimal solution if you don’t know what solution you’re optimizing. The two-pointer technique is an optimization technique, so unless you’re 101% confident in your solution, I believe, it might not be the best technique to jump into as a naive solution.

首先,如果您不知道要优化的解决方案,就无法想到最佳解决方案。 两点技术是一种优化技术,因此,我认为,除非您对解决方案有101%的信心,否则它可能不是跳入初始解决方案的最佳技术。

My rule of thumb is, if you encounter a problem that has your two-pass-approach-senses tingling, then opt for the two-pass approach first. You can’t go wrong with using it as your naive solution to start, and once you fleshed out your answer, you can analyze your code to determine if you can cut costs.

我的经验法则是,如果您遇到一个让您的两次通过方法感觉麻木的问题,那么请首先选择两次通过方法。 使用它作为您的幼稚解决方案来启动不会出错,一旦您充实了答案,就可以分析代码以确定是否可以削减成本。

It also makes excellent talking points during an interview. Remember, interviews are about assessing your problem-solving skills, not about how quickly you can conjure up an optimal solution.

在面试过程中,它也可以说出很好的谈话要点。 记住,面试是关于评估问题解决能力的,而不是关于您能多快地想到最佳解决方案。

You can show off your skills talking about:

您可以炫耀您谈论以下内容的技能:

  • Worst-case time and space complexity

    最坏的时间和空间复杂性
  • Discussing why the two-pass approach is efficient or inefficient

    讨论两次通过方法为何有效还是无效
  • Discussing ways to cut costs in your naive solution

    讨论在天真的解决方案中削减成本的方法
  • Discussing how the two-pointer technique could be implemented and possibly pseudo-code a solution.

    讨论如何实现两指针技术,并可能对解决方案进行伪编码。

As an interviewer, I would be much more impressed by a person who gave me a detailed, thorough analysis of a solution than someone who gave me an optimal solution right off the bat. So, never be afraid or ashamed to opt for a naive solution, like the two-pass approach first.

作为一名面试官,给一个给我一个详细,彻底的解决方案分析的人比给一个立即给我最佳解决方案的人留下深刻的印象。 因此,不要害怕或as愧选择天真的解决方案,例如首先采用两次通过方法。

You cannot go wrong with understanding both approaches. During your practice, I highly suggest solving problems using both and do a thorough analysis of both, as if you were in an interview. You’ll become a sharper problem solver and build those critical communication skills necessary for interacting with your future team.

了解这两种方法都不会出错。 在练习期间,我强烈建议同时使用这两种方法解决问题,并对它们进行彻底的分析,就好像您在接受采访时一样。 您将成为更敏锐的问题解决者,并建立与未来团队进行互动所必需的关键沟通技巧。

Happy coding!

编码愉快!

翻译自: https://levelup.gitconnected.com/two-pass-two-pointer-whats-the-difference-e006698db7c7

两个指针实现数组遍历

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值