Reduce size by half
Implement pow(x, n)
Implement pow(x, n).
Analysis
- 假设已知x^n,要求x^2n,那么则只需要一次运算,倒过来我们就可以通过x^n/2,来求pow(x,n). reduce size by half every time。接下来就只需要根据n为奇数或者偶数的不同,进行判断
- better than naive multiplication n times -> O(logn)
corner case when n < 0
只需要将x = 1/x,即可把n变回正值来计算
class Solution { private double fastPow(double x, long n) { if (n == 0) { return 1.0; } double half = fastPow(x, n / 2); if (n % 2 == 0) { return half * half; } else { return half * half * x; } } public double myPow(double x, int n) { long N = n; if (N < 0) { x = 1 / x; N = -N; } return fastPow(x, N); } };
Divide Two Integers
- 核心思路:转化成乘法考虑比较直接。看做divisor * multiple <= dividend. 为了从O(n)优化到O(logn),multiple的变化为1, 2, 4, ... 2^n
- 在具体实现中,是通过sum的翻倍递增来实现的, sum从divisor开始
ans = ans + recursive(dividend - sum, divisor)
- overflow case:
- anything / 0
- Integer.MIN_VALUE / -1
class Solution {
public int divide(int dividend, int divisor) {
if (divisor == 0 || dividend == Integer.MIN_VALUE && divisor == -1) return Integer.MAX_VALUE;
if (dividend == 0) return 0;
boolean neg = false;
if ((divisor < 0 && dividend > 0) ||
(divisor > 0 && dividend < 0))
neg = true;
long ldivisor = Math.abs((long)divisor);
long ldividend = Math.abs((long)dividend);
int ans = (int)divide(ldividend, ldivisor);
return neg ? -ans : ans;
}
private long divide(long ldividend, long ldivisor) {
if (ldividend == 0 || ldividend < ldivisor) return 0;
long multiple = 1;
long sum = ldivisor;
while (sum + sum <= ldividend) {
sum += sum;
multiple += multiple;
}
return multiple + divide(ldividend - sum, ldivisor);
}
}
Maximum Average Subarray II
Given an array with positive and negative numbers, find the maximum average subarray which length should be greater or equal to given length k. Given nums = [1, 12, -5, -6, 50, 3], k = 3 Return 15.667 // (-6 + 50 + 3) / 3 = 15.667
Analysis
- reduce size by half every time
- 一个数组的子数组的最大平均数一定在数组的最大值和最小值之间,所以二分法的第一步限定average位于[min,max]之中。
- 接下去要做的就是不断的缩小范围,直至max-min足够小(如1e-6),那我们就得到了想要的结果。
- 每一轮设置mid=(min+max)/2,然后将原数组中的每一个数减去这个mid,如果能找到(经过提醒,改正为:大于等于)k个相邻数的总和大于0的情况,那么说明最终结果一定比这个mid要更大,限定下一轮寻找范围在[mid,max]之中。反之在限定在[min,mid]之中。
Find median in 2 sorted Array
1.方法是每次在两个array(合并起来)取前k个,如果平均取,在A中取k/2个,在B中取k/2个,那么比较A和B中这两个位置处的大小可以知道,
- 比较A和B各自选到的数
- if (A[k/2] > B[k/2]) 则知道B中前k/2个肯定是较小的那些,在要取得第k个的时候,肯定是要被抛弃掉的。所以接下来在完整的A和从k/2处开始的B中,找第k-k/2个数,这里不直接用k/2是为了避免奇偶的问题
- if (A[k/2] < B[k/2])
- 因为扔去的是较小的树,所以只需要记录下startIndex
- corner case,需要检查startA + k / 2 - 1是否溢出
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int len = nums1.length + nums2.length;
if (len % 2 == 1)
return findKth(nums1, nums2, 0, 0, len/2+1);
else
return (findKth(nums1, nums2, 0, 0, len/2) + findKth(nums1, nums2, 0, 0, len/2+1)) / 2.0;
}
private double findKth(int[] nums1, int[] nums2, int start1, int start2, int k) {
if (start1 >= nums1.length)
return nums2[start2+k-1];
if (start2 >= nums2.length)
return nums1[start1+k-1];
if (k == 1)
return Math.min(nums1[start1], nums2[start2]);
int key1 = start1+ k / 2 - 1 < nums1.length ? nums1[start1+k/2-1] : Integer.MAX_VALUE;
int key2 = start2+ k / 2 - 1 < nums2.length ? nums2[start2+k/2-1] : Integer.MAX_VALUE;
if (key1 < key2) {
return findKth(nums1, nums2, start1+k/2, start2, k - k/2);
} else {
return findKth(nums1, nums2, start1, start2+k/2, k - k/2);
}
}
2.方法是假设最终的中位数在合并后的数组的k-1,或者k处,这个时候在两个array里,分别取了m1,m2个数。 则有
m1+m2 = k = (n1+n2+1)/2 //n1+n2+1是合并后数组的长度,因为这个时候k是中位数,在这里利用了中位数的性质
接下来的目标就是看如何找到m1。由分析我们可以知道Ck-1必定是Am1-1, Bm2-1中较大的。Ck必定是Am1, Bm2中较小的。于是可以通过Binary Search 来寻找m1,target是Bm2-1

- 注意边界条件有可能m1=0或者n1-1。
- 复杂度是O(log(min(n1,n2)))所以可以在一开始判断两个数组大小,对于较小的数组进行操作
- 注意m1这里是用了几个数,所以二分搜索时候r可以取到n1