面试题68:
问题:
输入一个排序的整形数组nums和一个目标值t,如果数组nums中包含t,则返回在数组中的下标,否则返回按照顺序插入到数组的下标。
解决方案:
使用二分查找。每次二分查找都选取位于数组中间下标的值,如果目标值等于当前值,返回当前下标。如果目标值大于当前值,那么目标值位于数组后半部分,如果目标值小于当前值,那么目标值位于数组前半部分。
源代码:
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while(left <= right){
int mid = (left+right)/2;
if(nums[mid] >= target){
if(mid == 0 || nums[mid - 1] < target){
return mid;
}
right = mid - 1;
}else{
left = mid + 1;
}
}
return nums.length;
}
}
面试题69:
问题:
在一个长度大于或等于3的数组中,找到数组最大值对应的下标。
解决方案:
使用二分查找。因为该数组是先递增后递减就像一座山峰,我们要求峰顶的下标,因此需要找到比它左右两边数字都大的数字对应的下标,如果这个数字比它左边的数字大,并且比它右边的数字要小,故峰顶在后半部分,如果这个数字比它左边的数字小,并且比它右边的数字要大,故峰顶在前半部分。
源代码:
class Solution {
public int peakIndexInMountainArray(int[] arr) {
int left = 1;
int right = arr.length - 2;
while(left <= right){
int mid = (left + right) / 2;
if(arr[mid] > arr[mid+1] && arr[mid] > arr[mid - 1]){
return mid;
}
if(arr[mid] > arr[mid - 1]){
left = mid + 1;
}else{
right = mid - 1;
}
}
return -1;
}
}
面试题70:
问题:
在一个排序的数组中找出唯一只出现一次的数字。
解决方案:
- 使用二进制。因为两个相同的数字异或的结果是0,将数组的所有数字进行异或,那么最终结果就是出现一次的数字。
- 在一个排序的数组中,将数组中的数字两两分组,最初的若干组的两个数字都是相同的,一旦遇到只出现一次的数字之后,后面的组全是不相同的,故出现不同的第一组的第一个数字就是出现一次的数字。
- 使用二分查找。先找出位于中间的一组,确定该组的两个数字是否相同,如果两个数字相同,那么只出现一次的数字在数组后半部分。如果两个数字不相同,需要继续判断该组是不是第一组,如果是第一组,那么该组的第一个数字就是出现一次的数字。如果不是第一组,那么只出现一次的数字在数组前半部分。
源代码:
class Solution {
public int singleNonDuplicate(int[] nums) {
int left = 0;
int right = nums.length/2;
while(left <= right){
int mid = (left + right)/2;
int i = mid * 2;
if(i < nums.length - 1 && nums[i] != nums[i + 1]){
if(mid == 0 || nums[i - 2] == nums[i - 1]){
return nums[i];
}
right = mid - 1;
}else{
left = mid + 1;
}
}
return nums[nums.length - 1];
}
}
面试题71:
问题:
输入一个正整数数组w,实现一个函数pickIndex根据权重比例随机选择一个下标。
解决方案:
使用二分查找。创建一个和权重数组的长度一样的数组sums,新数组的第i个数值sums[i]是权重数组中前i个数字之和。生成一个随机数p,先选取位于数组中间下标的值,如果p小于当前值,再判断p与前一位的值的大小,如果前一位的值小于等于p,那么返回当前下标,如果p大于当前值,那么权重值在数组前半部分,如果p大于当前值,那么权重值在数组后半部分。
源代码:
class Solution {
private int[] sums;
private int total;
public Solution(int[] w) {
sums = new int[w.length];
for(int i = 0;i < sums.length;i++){
total += w[i];
sums[i] = total;
}
}
public int pickIndex() {
Random random = new Random();
int p = random.nextInt(total);
int left = 0;
int right = sums.length - 1;
while(left <= right){
int mid = (left + right)/2;
if(sums[mid] > p){
if(mid == 0 || sums[mid - 1] <= p){
return mid;
}
right = mid - 1;
}else{
left = mid + 1;
}
}
return -1;
}
}