数据结构之区间,数组,矩阵——算法模板和相关题目

大纲

. Merge Two / K Sorted Arrays / Intervals 
. Median of Unsorted / Two Sorted / K Sorted Arrays

6. 合并排序数组 II

中文English

合并两个有序升序的整数数组A和B变成一个新的数组。新数组也要有序。

Example

样例 1:

输入: A=[1], B=[1]
输出:[1,1]	
样例解释: 返回合并后的数组。

样例 2:

输入: A=[1,2,3,4], B=[2,4,5,6]
输出: [1,2,2,3,4,4,5,6]	
样例解释: 返回合并后的数组。

Challenge

你能否优化你的算法,如果其中一个数组很大而另一个数组很小?

 

使用两个指针分别对数组从小到大遍历,每次取二者中较小的放在新数组中。
直到某个指针先到结尾,另一个数组中剩余的数字直接放在新数组后面。

时间复杂度O(n)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution:
    """
    @param A: sorted integer array A
    @param B: sorted integer array B
    @return: A new sorted integer array
    """
    def mergeSortedArray(self, A, B):
        i, j = 0, 0
        C = []
        while i < len(A) and j < len(B):
            if A[i] < B[j]:
                C.append(A[i])
                i += 1
            else:
                C.append(B[j])
                j += 1
        while i < len(A):
            C.append(A[i])
            i += 1
        while j < len(B):
            C.append(B[j])
            j += 1
             
        return C

  

64. 合并排序数组

中文English

合并两个排序的整数数组A和B变成一个新的数组。

Example

样例 1:

输入:[1, 2, 3]  3  [4,5]  2
输出:[1,2,3,4,5]
解释:
经过合并新的数组为[1,2,3,4,5]

样例 2:

输入:[1,2,5] 3 [3,4] 2
输出:[1,2,3,4,5]
解释:
经过合并新的数组为[1,2,3,4,5]

Notice

你可以假设A具有足够的空间(A数组的大小大于或等于m+n)去添加B中的元素。

分析:涉及两个有序数组合并,设置i和j双指针,分别从两个数组的尾部想头部移动,并判断A[i]和B[j]的大小关系,从而保证最终数组有序,同时每次index从尾部向头部移动。---双指针

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
class Solution:
    """
    @param: A: sorted integer array A which has m elements, but size of A is m+n
    @param: m: An integer
    @param: B: sorted integer array B which has n elements
    @param: n: An integer
    @return: nothing
    """
    def mergeSortedArray(self, A, m, B, n):
        # write your code here
        pos = m + n - 1
        i = m - 1 
        j = n - 1
        while  i >= 0 and j >= 0 :
            if A[i]>B[j] :
                A[pos]=A[i]
                pos-=1
                i-=1
            else :
                A[pos]=B[j]
                pos-=1
                j-=1
                 
        while i >= 0 :
            A[pos] = A[i]
            pos-=1
            i-=1
        while j >= 0:
            A[pos] = B[j]
            pos-=1
            j-=1

  

839. 合并两个排序的间隔列表

中文English

合并两个已排序的区间列表,并将其作为一个新的有序区间列表返回。新的区间列表应该通过拼接两个列表的区间并按升序排序。

Example

样例1

输入: [(1,2),(3,4)] and list2 = [(2,3),(5,6)]
输出: [(1,4),(5,6)]
解释:
(1,2),(2,3),(3,4) --> (1,4)
(5,6) --> (5,6)

样例2

输入: [(1,2),(3,4)] 和 list2 = [(4,5),(6,7)]
输出: [(1,2),(3,5),(6,7)]
解释:
(1,2) --> (1,2)
(3,4),(4,5) --> (3,5)
(6,7) --> (6,7)

Notice

同一个列表中的区间一定不会重叠。
不同列表中的区间可能会重叠。

用一个 last 来记录最后一个还没有被放到 merge results 里的 Interval,用于和新加入的 interval 比较看看能不能合并到一起。
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
"""
Definition of Interval.
class Interval(object):
    def __init__(self, start, end):
        self.start = start
        self.end = end
"""
 
class Solution:
    """
    @param list1: one of the given list
    @param list2: another list
    @return: the new sorted list of interval
    """
    def mergeTwoInterval(self, list1, list2):
        i, j = 0, 0
        intervals = []
        while i < len(list1) and j < len(list2):
            if list1[i].start < list2[j].start:
                self.push_back(intervals, list1[i])
                i += 1
            else:
                self.push_back(intervals, list2[j])
                j += 1
        while i < len(list1):
            self.push_back(intervals, list1[i])
            i += 1
        while j < len(list2):
            self.push_back(intervals, list2[j])
            j += 1
         
        return intervals
         
    def push_back(self, intervals, interval):
        if not intervals:
            intervals.append(interval)
            return
         
        last_interval = intervals[-1]
        if last_interval.end < interval.start:
            intervals.append(interval)
            return
         
        intervals[-1].end = max(intervals[-1].end, interval.end)

  

486. 合并k个排序数组

中文English

将 k 个有序数组合并为一个大的有序数组。

Example

样例 1:

输入:
  [
    [1, 3, 5, 7],
    [2, 4, 6],
    [0, 8, 9, 10, 11]
  ]
输出: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

样例 2:

输入: 
  [
    [1,2,3],
    [1,2]
  ]
输出: [1,1,2,2,3]

Challenge

在 O(N log k) 的时间复杂度内完成:

  • N 是所有数组包含的整数总数量。
  • k 是数组的个数。

可以用堆做到 O(N log k) 的时间复杂度.

初始将所有数组的首个元素入堆, 并记录入堆的元素是属于哪个数组的.

每次取出堆顶元素, 并放入该元素所在数组的下一个元素.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import heapq
 
 
class Solution:
    """
    @param arrays: k sorted integer arrays
    @return: a sorted array
    """
    def mergekSortedArrays(self, arrays):
        result = []
        heap = []
        for index, array in enumerate(arrays):
            if len(array) == 0:
                continue
            heapq.heappush(heap, (array[0], index, 0))
              
        while len(heap):
            val, x, y = heap[0]
            heapq.heappop(heap)
            result.append(val)
            if y + 1 < len(arrays[x]):
                heapq.heappush(heap, (arrays[x][y + 1], x, y + 1))
             
        return result

  

自顶向下的分治法

 
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
class Solution:
    """
    @param arrays: k sorted integer arrays
    @return: a sorted array
    """
    def mergekSortedArrays(self, arrays):
        return self.merge_range_arrays(arrays, 0, len(arrays) - 1)
         
    def merge_range_arrays(self, arrays, start, end):
        if start == end:
            return arrays[start]
         
        mid = (start + end) // 2
        left = self.merge_range_arrays(arrays, start, mid)
        right = self.merge_range_arrays(arrays, mid + 1, end)
        return self.merge_two_arrays(left, right)
         
    def merge_two_arrays(self, arr1, arr2):
        i, j = 0, 0
        array = []
        while i < len(arr1) and j < len(arr2):
            if arr1[i] < arr2[j]:
                array.append(arr1[i])
                i += 1
            else:
                array.append(arr2[j])
                j += 1
        while i < len(arr1):
            array.append(arr1[i])
            i += 1
        while j < len(arr2):
            array.append(arr2[j])
            j += 1
        return array

  

547. 两数组的交集

中文English

给出两个数组,写出一个方法求出它们的交集

Example

例1:

输入: nums1 = [1, 2, 2, 1], nums2 = [2, 2], 
输出: [2].

例2:

输入: nums1 = [1, 2], nums2 = [2], 
输出: [2].

Challenge

可以用三种不同的方法实现吗?

Notice

  • 结果中的每个元素必须是唯一的。
  • 结果需要为升序。

三种解法-----------倒排索引!!!

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// version 1: sort & merge
public class Solution {
    /**
     * @param nums1 an integer array
     * @param nums2 an integer array
     * @return an integer array
     */
    public int[] intersection(int[] nums1, int[] nums2) {
        Arrays.sort(nums1);
        Arrays.sort(nums2);
         
        int i = 0, j = 0;
        int[] temp = new int[nums1.length];
        int index = 0;
        while (i < nums1.length && j < nums2.length) {
            if (nums1[i] == nums2[j]) {
                if (index == 0 || temp[index - 1] != nums1[i]) {
                    temp[index++] = nums1[i];
                }
                i++;
                j++;
            } else if (nums1[i] < nums2[j]) {
                i++;
            } else {
                j++;
            }
        }
         
        int[] result = new int[index];
        for (int k = 0; k < index; k++) {
            result[k] = temp[k];
        }
         
        return result;
    }
}
 
// version 2: hash map
public class Solution {
    /**
     * @param nums1 an integer array
     * @param nums2 an integer array
     * @return an integer array
     */
    public int[] intersection(int[] nums1, int[] nums2) {
        if (nums1 == null || nums2 == null) {
            return null;
        }
         
        HashSet<Integer> hash = new HashSet<>();
        for (int i = 0; i < nums1.length; i++) {
            hash.add(nums1[i]);
        }
         
        HashSet<Integer> resultHash = new HashSet<>();
        for (int i = 0; i < nums2.length; i++) {
            if (hash.contains(nums2[i]) && !resultHash.contains(nums2[i])) {
                resultHash.add(nums2[i]);
            }
        }
         
        int size = resultHash.size();
        int[] result = new int[size];
        int index = 0;
        for (Integer num : resultHash) {
            result[index++] = num;
        }
         
        return result;
    }
}
 
// version 3: sort & binary search
public class Solution {
    /**
     * @param nums1 an integer array
     * @param nums2 an integer array
     * @return an integer array
     */
    public int[] intersection(int[] nums1, int[] nums2) {
        if (nums1 == null || nums2 == null) {
            return null;
        }
         
        HashSet<Integer> set = new HashSet<>();
         
        Arrays.sort(nums1);
        for (int i = 0; i < nums2.length; i++) {
            if (set.contains(nums2[i])) {
                continue;
            }
            if (binarySearch(nums1, nums2[i])) {
                set.add(nums2[i]);
            }
        }
         
        int[] result = new int[set.size()];
        int index = 0;
        for (Integer num : set) {
            result[index++] = num;
        }
         
        return result;
    }
     
    private boolean binarySearch(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return false;
        }
         
        int start = 0, end = nums.length - 1;
        while (start + 1 < end) {
            int mid = (end - start) / 2 + start;
            if (nums[mid] == target) {
                return true;
            }
            if (nums[mid] < target) {
                start = mid;
            } else {
                end = mid;
            }
        }
         
        if (nums[start] == target) {
            return true;
        }
        if (nums[end] == target) {
            return true;
        }
         
        return false;
    }
}

  

 

793. 多个数组的交集

中文English

给出多个数组,求它们的交集。输出他们交集的大小。

Example

样例 1:

	输入:  [[1,2,3],[3,4,5],[3,9,10]]
	输出:  1
	
	解释:
	只有3出现在三个数组中。

样例 2:

	输入: [[1,2,3,4],[1,2,5,6,7][9,10,1,5,2,3]]
	输出:  2
	
	解释:
	交集是[1,2].

基于 Priority Queue 的版本。
假设每个数组长度为 n, 一共 k 个数组。
时间复杂度为 O(knlogn + nklogk)
其中 knlogn 是 k 个数组进行分别排序的时间复杂度
nklogk 是 总共 nk 个数从 PriorityQueue 中进出,每次进出 logk。

相比使用 HashMap 的算法的时间复杂度 O(nk) 这个方法并没有什么时间上的优势。
但是这个方法的空间复杂度很低,只有 O(k),即多少个数组就花费多少的额外空间。

在面试中也是很有可能会被要求不用 HashMap 或者实现一个比 O(n) 更低的空间复杂度的算法。因此这个程序的方法也是需要掌握的。

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
public class Solution {
    class Pair {
        public int row, col;
         
        public Pair(int row, int col) {
            this.row = row;
            this.col = col;
        }
    }
     
    /**
     * @param arrs: the arrays
     * @return: the number of the intersection of the arrays
     */
    public int intersectionOfArrays(int[][] arrs) {
        Comparator<Pair> comparator = new Comparator<Pair>() {
          public int compare(Pair x, Pair y) {
            return arrs[x.row][x.col] - arrs[y.row][y.col];
          }
        };
         
        Queue<Pair> queue = new PriorityQueue<>(arrs.length, comparator);
         
        for (int i = 0; i < arrs.length; i++) {
            if (arrs[i].length == 0) {
                return 0;
            }
             
            Arrays.sort(arrs[i]);
            queue.offer(new Pair(i, 0));
        }
         
        int lastValue = 0, count = 0;
        int intersection = 0;
        while (!queue.isEmpty()) {
            Pair pair = queue.poll();
            if (arrs[pair.row][pair.col] != lastValue || count == 0) {
                if (count == arrs.length) {
                  intersection++;
                }
                lastValue = arrs[pair.row][pair.col];
                count = 1;
            } else {
                count++;
            }
             
            pair.col++;
            if (pair.col < arrs[pair.row].length) {
              queue.offer(pair);
            }
        }
         
        // kickoff the last number
        if (count == arrs.length) {
            intersection++;
        }
         
        return intersection;
    }
}

  

 

 

posted @   bonelee  阅读(528)  评论(3编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
历史上的今天:
2018-11-25 左转待转区----当同向直行信号灯绿灯亮时,左转弯的车辆进入左转待转区等候放行信号(即使此时左转弯灯是红色的) 注意:当直行红灯时候禁止进入
2018-11-25 可变导向车道——为了缓解高峰压力的临时转向车道
2017-11-25 ES业界优秀实践案例汇总
2016-11-25 javascript里的偏函数——本质函数式编程+闭包,返回函数
2016-11-25 javascript primise本质——为了简化异步编码而针对异步操作的代理
2016-11-25 JavaScript 运行机制详解:Event Loop——续
2016-11-25 JavaScript 运行机制详解:Event Loop
点击右上角即可分享
微信分享提示