定义局部最小的概念。arr长度为1时,arr[0]是局部最小。arr的长度为N(N>1)时,如果arr[0]
(1)判断左右两端的值是否为局部最小值
(2)二分搜索,判断mid的左右两边,比mid小的一边一定存在局部最小值;否则返回mid
public class Solution {
public int getLessIndex(int[] arr) {
if(arr==null||arr.length==0)
return -1;
int len = arr.length;
if(len==1||arr[0]<arr[1])
return 0;
if(arr[len-1]<arr[len-2])
return len-1;
int left = 1;
int right = len-2;
int mid = 0;
while(left<=right){
mid = (left+right)/2;
if(arr[mid]>arr[mid-1])
right = mid-1;
else if(arr[mid]>arr[mid+1])
left = mid+1;
else
return mid;
}
return -1;
}
}
对于一个有序数组arr,再给定一个整数num,请在arr中找到num这个数出现的最左边的位置。
给定一个数组arr及它的大小n,同时给定num。请返回所求位置。若该元素在数组中未出现,请返回-1。
测试样例:
[1,2,3,3,4],5,3
返回:2
思路:二分搜索,mid 位置的值把大于等于 num 的右边去掉 ,在剩余部分继续二分搜索,直到最后一个
public class LeftMostAppearance {
public int findPos(int[] arr, int n, int num) {
int left = 0;
int right = n-1;
int res = -1;
while(left<=right){
int mid = (left+right)/2;
if(arr[mid]>num)
right = mid-1;
else if(arr[mid]<num)
left = mid+1;
else{
right = mid-1;
res = mid;
}
}
return res;
}
}
对于一个有序循环数组arr,返回arr中的最小值。有序循环数组是指,有序数组左边任意长度的部分放到右边去,右边的部分拿到左边来。比如数组[1,2,3,3,4],是有序循环数组,[4,1,2,3,3]也是。
给定数组arr及它的大小n,请返回最小值。
测试样例:
[4,1,2,3,3],5
返回:1
思路:
(1)判断首尾,如果 a[0] < a[n-1],因为有序所以返回 a[0]
(2)否则,二分搜索 mid ,a[0]>a[mid]则在mid左边二分搜索,a[0] (3)若 a[0] == a[mid] ,则需要遍历数组
public class MinValue {
public int getMin(int[] arr, int n) {
if(arr==null||n==0)
return -1;
int left = 0;
int right = n-1;
int mid = 0;
if(n==1||arr[left]<arr[right])
return arr[left];
if(n==2)
return Math.min(arr[0],arr[1]);
while(left<right){
mid = (left+right)/2;
if(arr[left]>arr[mid]){
right = mid;
}else if(arr[left]<arr[mid]){
left = mid;
}else{
while(left<right){
if(arr[left]==arr[mid]){
left++;
}else if(arr[left]<arr[mid]){
return arr[left];
}else{
right = mid;
break;
}
}
}
}
return arr[left];
}
}
有一个有序数组arr,其中不含有重复元素,请找到满足arr[i]==i条件的最左的位置。如果所有位置上的数都不满足条件,返回-1。
给定有序数组arr及它的大小n,请返回所求值。
测试样例:
[-1,0,2,3],4
返回:2
思路:
(1)先判断数组两端,因为是有序数组,如果arr[0]>0或arr[n-1]
(3)当arr[mid]==mid时,接着二分搜索其左边。
public class Find {
public int findPos(int[] arr, int n) {
if(arr==null||n==0)
return -1;
int left = 0;
int right = n-1;
int res = -1;
while(left<=right){
if(arr[left]>left||arr[right]<right){
break;
}
int mid = (left+right)/2;
if(arr[mid]>mid){
right = mid-1;
}else if(arr[mid]<mid){
left = mid+1;
}else{
res = mid;
right = mid-1;
}
}
return res;
}
}
给定一棵完全二叉树的根节点root,返回这棵树的节点个数。如果完全二叉树的节点数为N,请实现时间复杂度低于O(N)的解法。
给定树的根结点root,请返回树的大小。
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}*/
public class CountNodes {
public int count(TreeNode root) {
int res = 0;
if(root == null)
return 0;
int left = getDepth(root.left);
int right = getDepth(root.right);
if(left==right){
res = (int)Math.pow(2,left);
res = res + count(root.right);
}else{
res = (int)Math.pow(2,right);
res = res + count(root.left);
}
return res;
}
//获取深度
private int getDepth(TreeNode tree){
int temp = 0;
while(tree!=null){
temp++;
tree = tree.left;
}
return temp;
}
}
如果更快的求一个整数k的n次方。如果两个整数相乘并得到结果的时间复杂度为O(1),得到整数k的N次方的过程请实现时间复杂度为O(logN)的方法。
给定k和n,请返回k的n次方,为了防止溢出,请返回结果Mod 1000000007的值。
测试样例:
2,3
返回:8
思路:
(1)10^75,75的二进制为1001011
(2)10^75 = 10^64 * 10^8 * 10^2 * 10^1, 由此可见,只需求出10,然后依据10求出10^2 ,依据10^2 求出10^4…
(3)而循环的次数为二进制数的位数,且只有为1时才乘到结果中
public class QuickPower {
public int getPower(int k, int N) {
if(k==1||N==0)
return 1;
long res = 1;
long temp = k;
int m = 1000000007;
while(N>0){
if((N&1)!=0)
res *= temp;
temp = (temp*temp)%m;//保证值在int的范围内
res = res%m;
N = N>>1;
}
return (int)res;
}
}