Dec 25, 26.
Mission:
- lintcode 459 Closest Number in Sorted Array
- lintcode 458 last-position-of-target
- lintcode 28 Search a 2D Matrix
- lintcode 585 Maximum Number in Mountain Sequence
- lintcode 447 Search in a Big Sorted Array
- lintcode 159 Find Minimum in Rotated Sorted Array
- lintcode 75 Find Peak Element
- lintcode 74 First Bad Version
- lintcode 62 leetcode33 Search in Rotated Sorted Array classic binary search question
- leetcode 81. Search in Rotated Sorted Array II O(n), to do
- lintcode 600 Smallest Rectangle Enclosing Black Pixels
- lintcode 462 Total Occurence of Target
- lintcode 254 Drop Eggs problem
- lintcode 14 First Position of Target, easy
- lintcode 460. k closest numbers in sorted array; leetcode 658 Find K Closest Elements
Codes
lintcode 459 Closest Number in Sorted Array
Standard binary search
- condition for stopping the loop: lo+1 < hi ===> will leave 2 indexes lo and hi.
- the final solution will be related to lo and hi.
package algorithm_ladder_II;
/**
* 在一个排好序的数组 A 中找到 i 使得 A[i] 最接近 target(存在重复元素时,可返回任意一个元素的下标)
* lintcode 459
*
*/
public class ClosestNumber {
public int findClosestNumber(int[] A, int target) {
// corner case:
if (A == null || A.length == 0) {
return -1;
}
int lo = 0, hi = A.length-1;
while (lo + 1 < hi) {
int mid = lo + (hi - lo) / 2;
if (A[mid] == target) {
return mid;
} else if (A[mid] > target) {
hi = mid;
} else {
lo = mid;
}
}
int diff_lo = Math.abs(A[lo] - target);
int diff_hi = Math.abs(A[hi] - target);
System.out.println("lo = " + lo + ", diff_lo = " + diff_lo);
System.out.println("hi = " + hi + ", diff_hi = " + diff_hi);
return diff_lo < diff_hi ? lo : hi;
}
public static void main(String[] args) {
int[] A = new int[] {1,2,3,7};
int target = -1;
ClosestNumber cn = new ClosestNumber();
System.out.println(cn.findClosestNumber(A, target)); // expected to be 3
}
}
lintcode 458 last-position-of-target
关键在于 target==A[mid] 时的判断
package algorithm_ladder_II;
/**
* 给一个升序数组,找到target最后一次出现的位置,如果没出现过返回-1
* 关键在于==mid时的判断
*/
public class LastTarget {
public int lastPosition(int[] A, int target) {
// corner case:
if (A == null || A.length == 0) {
return -1;
}
int lo = 0, hi = A.length-1;
while (lo + 1 < hi) {
int mid = lo + (hi - lo) / 2;
if (A[mid] > target) {
hi = mid;
} else {
lo = mid;
}
}
if (A[hi] == target) {
return hi;
} else if (A[lo] == target) {
return lo;
} else {
return -1;
}
}
public static void main(String[] args) {
int[] A = new int[] {1,2,2,2,4};
int target = 2;
LastTarget cn = new LastTarget();
System.out.println(cn.lastPosition(A, target)); // expected to be 2
}
}
lintcode 28 Search a 2D Matrix
Use binary search twice
package algorithm_ladder_II;
public class Search2DMatrix {
public boolean searchMatrix(int[][] matrix, int target) {
// corner case:
if (matrix == null || matrix.length == 0) {
return false;
}
int[] rowHead = new int[matrix.length];
for (int i = 0; i < matrix.length; i++) {
rowHead[i] = matrix[i][0];
}
int[] searchRow = binarySearch(rowHead, target);
if (searchRow.length == 1) {
return true;
}
int loValue = matrix[searchRow[0]][0], hiValue = matrix[searchRow[1]][0];
int theRowToSearch = -1;
if (target == loValue || target == hiValue) return true;
if (loValue > target) {
return false;
} else if (target > hiValue) {
theRowToSearch = searchRow[1];
} else {
theRowToSearch = searchRow[0];
}
System.out.println("the row to search: " +theRowToSearch);
int[] result = binarySearch(matrix[theRowToSearch], target);
if (result.length == 1) return true;
loValue = matrix[theRowToSearch][result[0]];
hiValue = matrix[theRowToSearch][result[1]];
if (target == loValue || target == hiValue) return true;
return false;
}
private int[] binarySearch (int[] A, int target) {
int lo = 0, hi = A.length -1;
while (lo+1 < hi) {
int mid = lo + (hi-lo) / 2;
if (A[mid] == target) {
return new int[] {mid};
} else if (target > A[mid]) {
lo = mid;
} else {
hi = mid;
}
}
return new int[] {lo, hi};
}
public static void main(String[] args) {
int[][] A = new int[3][4];
A[0] = new int[] {1,2,5,7};
A[1] = new int[] {10,11,16,20};
A[2] = new int[] {23,30,34,50};
int target = 3;
Search2DMatrix sd = new Search2DMatrix();
System.out.println(sd.searchMatrix(A, target)); // should be true
}
}
lintcode 585 Maximum Number in Mountain Sequence
Given a mountain sequence of n integers which increase firstly and then decrease, find the mountain top.
package algorithm_ladder_II;
/**
* Given a mountain sequence of n integers which increase firstly and then decrease, find the mountain top.
* 区间两端点一阶导数异号
*/
public class MaxNumMountSeq {
public int findMaxNum(int[] A) {
// corner case
if (A == null || A.length < 3) {
return -1;
}
int lo = 0, hi = A.length-1;
if (!(A[lo] < A[lo+1]) && !(A[hi-1] > A[hi])) { // not mountain sequence
return -1;
}
while (lo+1 < hi) {
int mid = lo + (hi-lo) / 2;
if (A[mid] > A[mid-1] && A[mid] > A[mid+1]) {
return mid;
} else if (A[mid] > A[mid-1]) {
lo = mid;
} else {
hi = mid;
}
}
if (A[lo] > A[lo-1] && A[lo] > A[lo+1]) {
return lo;
} else {
return hi;
}
}
public static void main(String[] args) {
int[] A = new int[] {1,2,3,4,5,9,8,4,3,1,-1};
MaxNumMountSeq mnms = new MaxNumMountSeq();
System.out.println(mnms.findMaxNum(A)); // expected to be 5
}
}
Lintcode 447
给一个按照升序排序的正整数数组。这个数组很大以至于你只能通过固定的接口 ArrayReader.get(k) 来访问第k个数。并且你也没有办法得知这个数组有多大。找到给出的整数target第一次出现的位置。你的算法需要在O(logk)的时间复杂度内完成,k为target第一次出现的位置的下标。如果找不到target,返回-1。
要点:可认为整个数组是无限长,递增的。使用乘法增加的思想探测index>target的地方。
package algorithm_ladder_II;
/**
* LintCode 447
* 给一个按照升序排序的正整数数组。这个数组很大以至于你只能通过固定的接口 ArrayReader.get(k) 来访问第k个数。
* 并且你也没有办法得知这个数组有多大。找到给出的整数target第一次出现的位置。
* 你的算法需要在O(logk)的时间复杂度内完成,k为target第一次出现的位置的下标。如果找不到target,返回-1
*
*/
public class SearchInBigArray {
public int findIndex(int target) {
int i = 0;
if (ArrayReader.get(i) == target) {
return I;
}
i = 1;
while (ArrayReader.get(i) < target) {
i *= 2;
}
int lo = i/2, hi = I;
while (lo + 1 < hi) {
int mid = lo + (hi-lo) / 2;
if (ArrayReader.get(mid) >= target) {
hi = mid;
} else {
lo = mid;
}
}
if (ArrayReader.get(lo) == target) {
return lo;
} else if (ArrayReader.get(hi) == target) {
return hi;
} return -1;
}
}
Find Minimum in Rotated Sorted Array
假设一个旋转排序的数组其起始位置是未知的(比如0 1 2 4 5 6 7 可能变成是4 5 6 7 0 1 2)。你需要找到其中最小的元素。你可以假设数组中不存在重复的元素。
要点:mid的判断
package algorithm_ladder_II;
/**
* leetcode 153, lintcode 159
*/
public class MinRotSortArr {
public int findMin(int[] A) {
// corner case;
if (A.length == 1) return A[0];
int lo = 0, hi = A.length-1;
while (lo+1 < hi) {
int mid = lo + (hi-lo)/2;
if (A[mid] < A[hi]) {
hi = mid;
} else {
lo = mid;
}
}
return Math.min(A[lo], A[hi]);
}
public static void main(String[] args) {
int[] A = new int[] {4, 5, 6, 7, 0, 1, 2};
MinRotSortArr mrsa = new MinRotSortArr();
System.out.println(mrsa.findMin(A)); // expected to be 0;
}
}
Lintcode 75 Find Peak Element
要点:根据mid是上升、下降、峰、谷分开判断
package algorithm_ladder_II;
/**
* Lintcode 75
* Find Peak Element
*
*/
public class PeakElem {
public int findPeak(int[] A) {
int lo = 0, hi = A.length-1;
while (lo + 1 < hi) {
int mid = lo + (hi-lo) / 2; // at least 3 elements in A
if (A[mid] > A[mid-1] && A[mid] > A[mid+1]) { // function shape: /\
return mid;
} else if (A[mid] < A[mid+1] && A[mid-1] < A[mid]) { // function shape: / /
lo = mid;
} else { // function shape: \/ OR \ \
hi = mid;
}
}
if (A[lo] > A[lo-1] && A[lo] > A[lo+1]) {
return lo;
} else {
return hi;
}
}
public static void main(String[] args) {
int[] A = new int[] {1, 2, 1, 3, 4, 5, 7, 6};
PeakElem pe = new PeakElem();
System.out.println(pe.findPeak(A)); // should be index 1 or 6
}
}
Lintcode 74 First bad version
要点:OOXX型找符合条件的最后一个
package algorithm_ladder_II;
/**
* lintcode 74
*
*/
public class FirstBadVersion {
public int findFirstBadVersion(int n) {
int lo = 1, hi = n;
while (lo+1 < hi) {
int mid = lo + (hi-lo) / 2;
if (SVNRepo.isBadVersion(mid)) {
hi = mid;
} else {
lo = mid;
}
}
if (SVNRepo.isBadVersion(lo)) {
return lo;
} else {
return hi;
}
}
}
leetcode 33. Search in Rotated Sorted Array
要点:多种情况的判断 (画图做题,把target区分在两个单调区间上讨论)
package algorithm_ladder_II;
public class SearchInRotSortArr {
public int search(int[] A, int target) {
// corner case
if (A == null || A.length == 0) {
return -1;
}
int lo = 0, hi = A.length-1;
while (lo +1 < hi) {
int mid = lo + (hi-lo)/2;
if (target > A[hi]) {
if (A[mid] == target) return mid;
if (A[mid] < A[hi]) hi = mid;
else if (A[mid] > target) hi = mid;
else lo = mid;
} else {
if (A[mid] == target) return mid;
if (A[mid] > A[hi]) lo = mid;
else if (A[mid] < target) lo = mid;
else hi = mid;
}
}
if (A[lo] == target) return lo;
if (A[hi] == target) return hi;
return -1;
}
public static void main(String[] args) {
int[] A = new int[] {4, 5, 6, 7, 0, 1, 2};
int target = 1;
SearchInRotSortArr srsa = new SearchInRotSortArr();
System.out.println(srsa.search(A, target)); // should be 5
}
}
leetcode 81. Search in Rotated Sorted Array II
重复元素导致不能根据导数来判断左右区间。
要点: No need to check two parts. We must have one part sorted while the other part rotated.
solution
public boolean search(int[] nums, int target) {
int start = 0, end = nums.length - 1;
//check each num so we will check start == end
//We always get a sorted part and a half part
//we can check sorted part to decide where to go next
while(start <= end){
int mid = start + (end - start)/2;
if(nums[mid] == target) return true;
//if left part is sorted
if(nums[start] < nums[mid]){
if(target < nums[start] || target > nums[mid]){
//target is in rotated part
start = mid + 1;
}else{
end = mid - 1;
}
}else if(nums[start] > nums[mid]){
//right part is rotated
//target is in rotated part
if(target < nums[mid] || target > nums[end]){
end = mid -1;
}else{
start = mid + 1;
}
}else{
//duplicates, we know nums[mid] != target, so nums[start] != target
//based on current information, we can only move left pointer to skip one cell
//thus in the worest case, we would have target: 2, and array like 11111111, then
//the running time would be O(n)
start ++;
}
}
return false;
}
lintcode 600, leetcode 302 Smallest Rectangle Enclosing Black Pixels
经典题, 可以逐层优化
- O(mn) brutal-force search
- DFS O(B), where B is number of black pixels. (similar to LeetCode200 number of islands)
- Binary search: 4 searches, searching for left, right, top, bottom bounds.
- when searching columns (left and right), use binary search in columns O(mlogn)
- when searching rows (top and bottom), use bs in rows O(nlogn)
package algorithm_ladder_II;
/**
* leetcode 302
* 4层binary search。二刷优化代码。
*/
public class SmallestRectangleEnclosingBlackPixels {
private char[][] A;
public int minArea(char[][] A, int x, int y) {
this.A = A;
int m = A.length; // numRows
int n = A[0].length; // numCols
int lo, hi;
int left, right, top, bottom;
// binary search for LEFT BOUND within col (0, y);
lo = 0; hi = y;
while (lo+1 < hi) {
int mid = lo + (hi-lo) /2;
if (!hasBlackPixel(mid, 0, m-1, true)) {
lo = mid;
} else {
hi = mid;
}
}
if (hasBlackPixel(lo, 0, m-1, true)) left = lo;
else left = hi;
// binary search for RIGHT BOUND within col (y, n);
lo = y; hi = n-1;
while (lo+1 < hi) {
int mid = lo + (hi-lo) /2;
if (hasBlackPixel(mid, 0, m-1, true)) {
lo = mid;
} else {
hi = mid;
}
}
if (hasBlackPixel(hi, 0, m-1, true)) right = hi;
else right = lo;
// bs for TOP BOUND within row (0, x);
lo = 0; hi = x;
while (lo + 1 < hi) {
int mid = lo + (hi-lo)/2;
if (!hasBlackPixel(mid, left, right, false)) {
lo = mid;
} else {
hi = mid;
}
}
if (hasBlackPixel(lo, left, right, false)) top = lo;
else top = hi;
// bs for bottom BOUND within row (x, m);
lo = x; hi = m-1;
while (lo+1 < hi) {
int mid = lo + (hi-lo) /2;
if (hasBlackPixel(mid, left, right, false)) {
lo = mid;
} else {
hi = mid;
}
}
if (hasBlackPixel(hi, left, right, false)) bottom = hi;
else bottom = lo;
System.out.println("left: " + left);
System.out.println("right: " + right);
System.out.println("top: " + top);
System.out.println("bottom: " + bottom);
//System.out.println(hasBlackPixel(2, 0, 3, false));
return (right - left + 1 ) * (bottom - top + 1);
}
private boolean hasBlackPixel(int colOrRow, int lowerBound, int upperBound, boolean isCol) {
if (isCol) { // search a column
for (int i = lowerBound; i<= upperBound; i++) {
if (A[i][colOrRow] == '1') {
return true;
}
}
return false;
} else { // search a row
for (int i = lowerBound; i<= upperBound; i++) {
if (A[colOrRow][i] == '1') {
return true;
}
}
return false;
}
}
public static void main(String[] args) {
char[][] A = new char[3][4];
A[0] = new char[] {'0','0','1','0'};
A[1] = new char[] {'0','1','1','0'};
A[2] = new char[] {'0','1','0','0'};
SmallestRectangleEnclosingBlackPixels s = new SmallestRectangleEnclosingBlackPixels();
System.out.println(s.minArea(A, 1, 2));
}
}
lintcode 462 Total occurrence of target
要点,两次二分法,查first and last (mid的判断)。
package algorithm_ladder_II;
/**
* Lintcode 462
* Given a target number and an integer array sorted in ascending order.
* Find the total number of occurrences of target in the array.
*
*/
public class TotalOccuranceTarget {
public int totalOccurance(int[] A, int target) {
if (A == null || A.length == 0) {
return 0;
}
int indexOfFirst = findTarget(A, target, true);
if (indexOfFirst == -1) return 0;
int indexOfLast = findTarget(A, target, false);
return indexOfLast - indexOfFirst + 1;
}
// findFirst = true : find the first target;
// findFirst = false : find the last target;
// return -1 if not found;
private int findTarget(int[] A, int target, boolean findFirst) {
int lo = 0, hi = A.length-1;
while (lo + 1 < hi) {
int mid = lo + (hi-lo) / 2;
if (target > A[mid]) {
lo = mid;
} else if (target < A[mid]) {
hi = mid;
} else {
if (findFirst) {
hi = mid;
} else {
lo = mid;
}
}
}
if (findFirst) {
if (A[lo] == target) return lo;
else if (A[hi] == target) return hi;
else return -1;
} else {
if (A[hi] == target) return hi;
else if (A[lo] == target) return lo;
else return -1;
}
}
public static void main(String[] args) {
int[] A = new int[] {1,2,3,4,4,4,4,4,6,6,6,6,9,10};
int target = 4;
TotalOccuranceTarget tot = new TotalOccuranceTarget();
System.out.println(tot.totalOccurance(A, target)); // should be 5
}
}
LintCode 254 Drop Eggs problem
一个general的最优化解: DP (see geek4geeks有很好的dp解这题的讨论)
回归到这道题,2个鸡蛋100楼,只需要n + (n-1) + (n-2) + ...+1 > 100 see 讨论
这道题值得讨论 -- to do
- 一个鸡蛋: brutal force
- 无数个鸡蛋:binary search
- n eggs, k storys: dynamic programming: f[I][j] = 1 + Max(f[i-1][j-1], f[i][k-j])
lintcode 14
search first , mid的判断。
package algorithm_ladder_II;
/**
* Lintcode 14 easy
*/
public class FirstPositionOfTarget {
public int binarySearch(int[] A, int target) {
// corner case;
if (A == null || A.length == 0)
return -1;
int lo = 0, hi = A.length-1;
while (lo + 1 < hi) {
int mid = lo + (hi-lo) / 2;
if (target > A[mid]) {
lo = mid;
} else if (target < A[mid]) {
hi = mid;
} else {
hi = mid;
}
}
if (A[lo] == target)
return lo;
else if (A[hi] == target)
return hi;
else
return -1;
}
public static void main(String[] args) {
int[] A = new int[] {1, 2, 3, 3, 4, 5, 10};
int target = 3;
FirstPositionOfTarget fp = new FirstPositionOfTarget();
System.out.println(fp.binarySearch(A, target)); // should be 2
}
}
lintcode 460 k closest numbers in sorted array; leetcode 658 Find K Closest Elements
我自己想的办法,先找到x的左右界left/right(如果array中没有x就找小于x的最大数,和大于x的最小数); O(log N)
再在[left-k, right-k]按照与x的difference来排序找出前几个。。。再排序返回。O(klogk);
看了一下别人的答案 很巧啊
- 先找first x (只用到lo and hi就可以了)
- 由[lo, hi] 双指针,不断线性扩张区间。
- Time complexity: O(logN + k);
package algorithm_ladder_II;
import java.util.LinkedList;
import java.util.List;
/**
* leetcode 658
*
*/
public class FindKClosestElements {
public List findClosestElements(int[] A, int k, int x) {
LinkedList res = new LinkedList();
// corner case
if (A == null || A.length == 0)
return res;
// search for first x;
int lo = 0, hi = A.length;
while (lo + 1 < hi) {
int mid = lo + (hi - lo) / 2;
if (x > A[mid]) {
lo = mid;
} else {
hi = mid;
}
}
// expanding ...
while (res.size() < k) {
if (lo >= 0 && hi < A.length) {
if (Math.abs(x - A[hi]) < Math.abs(x-A[lo])) {
res.addLast(A[hi]);
hi++;
} else {
res.addFirst(A[lo]);
lo--;
}
} else if (lo >= 0) {
res.addFirst(A[lo]);
lo--;
} else {
res.addLast(A[hi]);
hi++;
}
}
return res;
}
public static void main(String[] args) {
int[] A = new int[] {1,2,3,4,5};
int k = 4;
int x = 3;
FindKClosestElements f = new FindKClosestElements();
List res = f.findClosestElements(A, k, x);
for (int i : res) {
System.out.print(i + " "); // should be 1,2,3,4
}
}
}