1、前言
数组、链表、二叉树、动态规划、栈与队列是面试中常考的知识点,而在这几个知识点中,数组形式虽然简单,但是很灵活,在它基础上能衍生出很多问题,非常能考察人的编程思维,因此,本文对数组中常见的一些问题进行了总结,包括:
(1)递增排序数组旋转的最小数字;
(2)数字在排序数组中出现的次数;
(2)调整数组顺序,使数组中的奇数为与偶数的前面;
(3)数组中第K大的数;
(4)数组中最小的K个数;
(5)数组中出现次数超过一半的数字;
(7)把数组排成最小的数;
(8)数组中的逆序对;
(9)K-sum问题;
(10)数组中只出现一次的数字;
2、数组中常考的问题
将一个数组的开头若干个元素搬到数组的末尾,我们称之为数组的旋转,输入递增排序数组的一个旋转,比如{5,6,1,2,3},求旋转数组的最小元素。
(1)旋转数组的最小数字
基本思路:这种问题的解法有很多,方法1是你可以直接对数组进行排序,然后找出最小的数字即可,这种方法的时间复杂度为O(nlogn);方法2是对数组进行扫描,找到数组的最小元素,这种方法的时间复杂度为O(n);
还有一种方法,能在O(log)的时间解决这个问题。
由于原数组是递增的,旋转之后,部分有序,但只要是有序的,问题就会简单很多。
根据最小元素所在的位置,我们可以将数组划分成两个部分A和B,A、B都是递增的数组,且A的开头元素(数组的第一个元素)必定大于或等于B的结尾元素(数组的最后一个元素),(如果A和B长度都不为0的情况下)。我们可以借助二分查找的思想,
1)每次取出数组中间位置的元素middle,那么middle要么落在A中,要么落在B中;
2)如果middle落在A中,那么middle一定大于或等于第一个元素,这时最小元素在middle的后面部分;
3)如果middle落在B中,那么middle一定小于或等于最后一个元素,这时最小元素在middle的前面部分;
需要特别注意的是,
A、当middle同时等于A的开头元素、和B的结尾元素时,无法确定middle是落在A还是B,比如{1,0,1,1,1}和{1,1,1,0,1},这时,只能采用顺序查找的方法;
B、当旋转数组是原递增排序数组旋转0个元素得到时,数组的第一个元素小于最后一个元素,最小的元素是数组的第一个元素。
代码实现:
def MinNumInRoateArray(array):
if len(array) <= 0:
return
start = 0
end = len(array) - 1
if array[start] < array[end]:
return array[start]
min_num = None
while array[start] >= array[end]:
if end == (start + 1):
min_num = array[end]
break
middle = (start + end) // 2
if array[start] == array[end] and array[middle] == array[end]:
min_num = MinOrderSearch(array,start,end)
if array[middle] <= array[end]:
end = middle
elif array[middle] >= array[start]:
start = middle
return min_num
def MinOrderSearch(array,start,end):
min_num = float("inf")
for i in range(start,end + 1):
if array[i] < min_num:
min_num = array[i]
return min_num
(2)数字在排序数组中出现的次数
在一个非严格递增排序的数组中,求某个数字出现的次数,比如排序数组{1,2,3,3,4,5}中3出现的次数是2。
基本思路:假设要查找的数是number,我们可以在排序数组中找到第一个number出现的位置first,再找到最后一个number出现的位置end,end - first +1即是number出现的次数。所以问题转化成查找数组中第一个number的位置和最后一个number的位置,可以使用两次二分查找,
在查找第一个number时,取中间位置的元素middle和number比较,
如果middle小于number,则在middle的前半部分查找,如果小于middle,则在后半部分查找,
如果等于number,继续看middle前面一个元素是否等于number,如果等于,则说明middle不是第一个number,继续在middle的前半部分查找;
查找第二个number的方法类似。
代码实现:
def Number_Count(array,number):
if len(array) <= 0:
return 0
frequency = 0
first_index = BinarySearch(array,number,first=True)
last_index = BinarySearch(array,number,first=False)
if first_index != None and last_index != None:
frequency = last_index - first_index + 1
return frequency
def BinarySearch(array,number,first):
start = 0
end = len(array) - 1
number_index = None
while start < end:
middle = (start + end) // 2
if array[middle] < number:
start = middle + 1
elif array[middle] > number:
end = middle - 1
else:
if first == True:
if middle - 1 >= start and array[middle - 1] != number or (middle == start):
number_index = middle
break
else:
end = middle - 1
else:
if middle + 1 <= end and array[middle + 1] != number or (middle == end):
number_index = middle
break
else:
start = middle + 1
if number_index == None and array[end] == number:
number_index = end
return number_index