数据结构之区间,数组,矩阵——算法模板和相关题目
大纲
. 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)
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从尾部向头部移动。---双指针
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
同一个列表中的区间一定不会重叠。
不同列表中的区间可能会重叠。
"""
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) 的时间复杂度.
初始将所有数组的首个元素入堆, 并记录入堆的元素是属于哪个数组的.
每次取出堆顶元素, 并放入该元素所在数组的下一个元素.
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
自顶向下的分治法
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
- 结果中的每个元素必须是唯一的。
- 结果需要为升序。
三种解法-----------倒排索引!!!
// 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) 更低的空间复杂度的算法。因此这个程序的方法也是需要掌握的。
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;
}
}

浙公网安备 33010602011771号