数据结构之区间,数组,矩阵——算法模板和相关题目
大纲
. Merge Two / K Sorted Arrays / Intervals
. Median of Unsorted / Two Sorted / K Sorted Arrays
6. 合并排序数组 II
合并两个有序升序的整数数组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. 合并排序数组
合并两个排序的整数数组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. 合并两个排序的间隔列表
合并两个已排序的区间列表,并将其作为一个新的有序区间列表返回。新的区间列表应该通过拼接两个列表的区间并按升序排序。
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
同一个列表中的区间一定不会重叠。
不同列表中的区间可能会重叠。
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个排序数组
将 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. 两数组的交集
给出两个数组,写出一个方法求出它们的交集
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. 多个数组的交集
给出多个数组,求它们的交集。输出他们交集的大小。
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; } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.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