两个指针-TwoPointer

[两个指针] (Two Pointer)

两个指针的题目主要分成三种情况:

a.对撞型

  1. 2Sum 类
    例题: Trapping Water
    一个指针i指向数组头,一个指针j指向数组尾。

    1
    2
    3
    4
    5
    6
    7
    while i != j:
    if num[i] < num[j]:
    i += 1
    elif num[i] > num[j]:
    j -= 1
    else:
    i += 1
  2. Partition类
    例题: 将一个数组分成两部分,一部分小与k,一部分大于k
    一个指针i指向数组头,一个指针j指向数组尾。i表示在i之前的元素都小于k,j表示在j之后的元素都大于k。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    while i != j:
    while num[i] < k:
    i += 1
    while num[j] > k:
    j -= 1
    if i > j:
    break
    else:
    swap(i, j)

总结
通过对撞型指针优化算法,根本上其实要证明不用扫描多余状态

b.前向型

  1. 窗口类
    例题: Minimum Window Substring
    窗口类指针模板j

    1
    2
    3
    4
    5
    6
    7
    8
    j = 0
    for i in xrange(n):
    while j < n:
    if 满足条件:
    j += 1
    更新状态
    else 不满足条件:
    break
  2. 快慢类
    两个指针i, j的pace不同,可以用来探测一个链表是否有回路

总结
窗口类的问题根本上其实也是要证明不用扫描多余状态
快慢类的问题感觉和经常见的烧蜡烛的那种智力题很像。或者是环绕一圈来找list有没有cycle。

c.两个数组,两个指针

  1. 并行
    例题: Merge Two Sorted Array
    单纯的是否两个指针

每日一刷-Count of Smaller Numbers After Self

[每日一刷] (Count of Smaller Numbers After Self)


You are given an integer array nums and you have to return a new counts array.
The counts array has the property where counts[i] is the number of smaller elements to the right of nums[i].

Example:
Given nums = [5, 2, 6, 1]
Return the array [2, 1, 1, 0]

解题思路


这题其实又是一个有关区间的题,每次都找当前值后面有多少个比它小的数。因此马上可以想到用线段树。
这道题其实就是值线段树的简单应用,线段树结点中存储一个区间内有多少个值,然后每次查询后修改线段树。
这题主要就是各种边界条件比较多,下次要注意。

Python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
"""
时间复杂度 O(nlog(n))
"""
class SegmentTree(object):
def __init__(self, d, nums, left, right):
self.left, self.right = left, right
self.val = 0
self.mid = self.left + (self.right - self.left) / 2
self.c1 = self.c2 = None
if self.left == self.right:
self.val = d[self.left]
else:
self.c1 = SegmentTree(d, nums, self.left, self.mid)
self.c2 = SegmentTree(d, nums, self.mid+1, self.right)
self.val = self.c1.val + self.c2.val
def query(self, right):
if right < self.left:
return 0
if self.right == self.left:
return self.val
if self.right == right:
return self.val
else:
if right <= self.mid:
return self.c1.query(right)
else:
return self.c1.query(self.mid) + self.c2.query(right)
def modify(self, index):
if self.left == self.right and self.left == index:
self.val -= 1
else:
if index <= self.mid:
self.c1.modify(index)
else:
self.c2.modify(index)
self.val = self.c1.val + self.c2.val
class Solution(object):
def countSmaller(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
if nums == []:
return []
left, right = min(nums), max(nums)
for i in xrange(len(nums)): # deal with numbers below zero.
nums[i] -= left
right -= left
d = [0 for i in xrange(right+1)]
for i in nums:
d[i] += 1
tree = SegmentTree(d, nums, 0, right) # build segment tree.
res = []
for i in nums:
temp = tree.query(i-1)
res.append(temp)
tree.modify(i) # modify the tree after each query
return res