53 数字在升序数组中出现的次数
给定一个长度为 n 的非降序数组和一个非负数整数 k ,要求统计 k 在数组中出现的次数
要求:空间复杂度 O(1),时间复杂度 O(logn)
思路:二分法。
1.mid=array.length/2 ; 分成[0,mid] [mid+1;length-1]
if(array[mid]<k) 则对[mid+1;length-1]二分,否则在[0,mid]二分。
2.设置-1,以说明没找到,没找到就回0
3.找到mid 后,看之前之后一位在不在下标范围内且等不等于k,若相等继续推,不等直接返回mid
递归写法,while都行*/
public class Solution {
public int GetNumberOfK(int [] array , int k) {
if(array == null || array.length == 0) return 0;
int first=GetFirst( 0, array.length-1, k,array);
int last=GetLast( 0, array.length-1, k,array);
if(first > -1 && last > -1) return last - first + 1;//找到了,就做差+1
return 0;//如果左右都是-1,说明没有找到K,应该直接返回0
}
int GetFirst(int start,int end,int k,int[] arr){
if(start>end) return -1;
int mid=start+(end-start)/2;
if(arr[mid]>k) return GetFirst(start,mid-1,k,arr);
if(arr[mid]<k) return GetFirst(mid+1,arr.length-1,k,arr);
else{ //最大困惑是怎么找前面的k....若前面那个数也==k那么继续递归
if(mid-1>=0&&arr[mid-1]==k) return GetFirst(start,mid-1,k,arr);
else return mid;}
}
int GetLast(int start,int end,int k,int[] arr){
while(start<=end){
int mid=start+(end-start)/2;
if(arr[mid]>k) end=mid-1;
else if(arr[mid]<k) start=mid+1;
else{
if(mid+1<=end&&arr[mid+1]==k) start=mid+1;
else return mid; }
mid=(start+end)<<2; }
return -1;
}
}
4 二维数组中的查找
在一个二维数组array中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]
给定 target = 7,返回 true。
给定 target = 3,返回 false。
进阶:空间复杂度 O(1)O(1) ,时间复杂度 O(n+m)
思路:从左下角看,若大于则右,小于则上,等于则返回(行列一定要在范围内)
public class Solution {
public boolean Find(int target, int [][] array) {
int row=array.length-1;
int low=0;
while(row>=0&&low<=array[0].length-1){
if(array[row][low]>target) row--;
else if(array[row][low]<target) low++;
else return true;
}
return false;
}
}
11 旋转数组的最小数字
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
要求:空间复杂度:O(1) ,时间复杂度:O(logn)
思路:非降序数组,那么以中间值为基准,arr[mid]>arr[end]的话那么最小值应该mid后面;
否则high==mid(即中间值<右边,则以中间值为右边界,因为中间值为分界线,两边都是递增,右边递增包不包括中间元素2说;当中间值==右边边界得时候,那么右边界向前移动继续判断(总会移动到最小值那里)
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length<=0) return 0;
int low=0; int high=array.length-1;
while(low<high){
int mid=low+(high-low)/2;
if(array[mid]>array[high]) low=mid+1;
else if(array[mid]<array[high]) high=mid;
else high--;
}
return array[low];
}
}
44 数字序列中某一位的数字
数字以 0123456789101112131415... 的格式作为一个字符序列,在这个序列中第 2 位(从下标 0 开始计算)是 2 ,第 10 位是 1 ,第 13 位是 1 ,以此类题,请你输出第 n 位对应的数字。
思路:【1,9】 1x9=9; [10,99] 2x90=180; [100,999] 3x900=2700
1.先求n在哪个区间里面 n-9-180-2700直到小于0即可
int base=1; int count=1;(位数)
while(n-base*9*count>0){
n-=9*base*count;base=base*10;count++;
}//循环结束时候的base是我们的区间的起始值,这时候的n也是....'
2.对n取余,若无余数就是之前哪个数//191-189=2--100,193-189=4--101
int len=n%count; int num=base+(n-1)/count;
import java.util.*;
public class Solution {
public int findNthDigit (int n) {
int count=1;//每一个区间的位数
int base=1;
while(n-9*base*count>0){ //190
n-=9*base*count;//181-180=1
base=base*10;
count++; }
//while循环出来得到n已经到了数值所处的区间,以及位数,
//base区间起步
int curNum=(n-1)/count+base;//所求num
int resDigit = 0;
for (int i=n%count; i<count; i++){
resDigit = curNum % 10;
curNum /= 10;
}
return resDigit;
}
}