Showing posts with label binary search. Show all posts
Showing posts with label binary search. Show all posts

Wednesday, November 28, 2018

911. Online Election

911Online Election
In an election, the i-th vote was cast for persons[i] at time times[i].
Now, we would like to implement the following query function: TopVotedCandidate.q(int t) will return the number of the person that was leading the election at time t.  
Votes cast at time t will count towards our query.  In the case of a tie, the most recent vote (among tied candidates) wins.

Example 1:
Input: ["TopVotedCandidate","q","q","q","q","q","q"], [[[0,1,1,0,0,1,0],[0,5,10,15,20,25,30]],[3],[12],[25],[15],[24],[8]]
Output: [null,0,1,1,0,0,1]
Explanation: 
At time 3, the votes are [0], and 0 is leading.
At time 12, the votes are [0,1,1], and 1 is leading.
At time 25, the votes are [0,1,1,0,0,1], and 1 is leading (as ties go to the most recent vote.)
This continues for 3 more queries at time 15, 24, and 8.

Note:
  1. 1 <= persons.length = times.length <= 5000
  2. 0 <= persons[i] <= persons.length
  3. times is a strictly increasing array with all elements in [0, 10^9].
  4. TopVotedCandidate.q is called at most 10000 times per test case.
  5. TopVotedCandidate.q(int t) is always called with t >= times[0].
--------------------------
预先生成好答案。调用q的时候用binary search。这里简单一点用treemap来作个弊
constructor O(n), q O(lg n)

class TopVotedCandidate {
    
    private TreeMap<Integer, Integer> winners;
    public TopVotedCandidate(int[] persons, int[] times) {
        winners = new TreeMap<>();
        Map<Integer, Integer> personToVotes = new HashMap<>();
        int winner = -1;
        personToVotes.put(winner, 0);
        
        for (int i = 0; i < persons.length; i++) {
            int p = persons[i];
            
            personToVotes.put(p, personToVotes.getOrDefault(p, 0) + 1);
            if (personToVotes.get(p) >= personToVotes.get(winner)) {                
                winner = p;
            }
            
            winners.put(times[i], winner);
        }
    }
    
    public int q(int t) {
        return winners.floorEntry(t).getValue();
    }
}

/**
 * Your TopVotedCandidate object will be instantiated and called as such:
 * TopVotedCandidate obj = new TopVotedCandidate(persons, times);
 * int param_1 = obj.q(t);
 */

Sunday, November 18, 2018

374. Guess Number Higher or Lower, 375. Guess Number Higher or Lower II

374Guess Number Higher or Lower
We are playing the Guess Game. The game is as follows:
I pick a number from 1 to n. You have to guess which number I picked.
Every time you guess wrong, I'll tell you whether the number I picked is higher or lower.
However, when you guess a particular number x, and you guess wrong, you pay $x. You win the game when you guess the number I picked.
Example:
n = 10, I pick 8.

First round:  You guess 5, I tell you that it's higher. You pay $5.
Second round: You guess 7, I tell you that it's higher. You pay $7.
Third round:  You guess 9, I tell you that it's lower. You pay $9.

Game over. 8 is the number I picked.

You end up paying $5 + $7 + $9 = $21.
Given a particular n ≥ 1, find out how much money you need to have to guarantee a win.
----------------------

/* The guess API is defined in the parent class GuessGame.
   @param num, your guess
   @return -1 if my number is lower, 1 if my number is higher, otherwise return 0
      int guess(int num); */

public class Solution extends GuessGame {
    public int guessNumber(int n) {
        int left = 1, right = n;
        
        while (left <= right) {
            int mid = (right - left) / 2 + left;
            int rt = guess(mid);
            if (rt == 0) return mid;
            if (rt > 0) {
                left = mid + 1;
            }else {
                right = mid - 1;
            }
        }
        
        return left;
    }
}

375Guess Number Higher or Lower II
We are playing the Guess Game. The game is as follows:
I pick a number from 1 to n. You have to guess which number I picked.
Every time you guess wrong, I'll tell you whether the number I picked is higher or lower.
However, when you guess a particular number x, and you guess wrong, you pay $x. You win the game when you guess the number I picked.
Example:
n = 10, I pick 8.

First round:  You guess 5, I tell you that it's higher. You pay $5.
Second round: You guess 7, I tell you that it's higher. You pay $7.
Third round:  You guess 9, I tell you that it's lower. You pay $9.

Game over. 8 is the number I picked.

You end up paying $5 + $7 + $9 = $21.
Given a particular n ≥ 1, find out how much money you need to have to guarantee a win.
-----------------------------
题意有点绕:找一个花费最小的通解
brute force的算法是枚举所有的可能性,找出最小(最优)的解。
给定[start, end], 猜i点之后的cost是cost[i] = i + Math.max(cost[start, i - end], cost[i + 1, end]), 取2者中间最大是因为不能确定最终结果在左还是在右
ref: https://leetcode.com/problems/guess-number-higher-or-lower-ii/solution/

Solution #1 DP 是对brute force的优化
重点:这题的2维DP是按对角线来填充,因为[len]是基于[len - i]...[len - 1]
以后写dp要理解其本身的通项公式
O(n^3)
class Solution {
    public int getMoneyAmount(int n) {
        int[][] dp = new int[n + 1][n + 1];
        
        for (int len = 2; len <= n; len++) {
            for (int start = 1; start < n - len + 2; start++) {
                int min = Integer.MAX_VALUE;
                for (int i = start; i <= start + len - 1; i++) {
                    
                    int v = 0;
                    if (i == start + len - 1) {
                        v = i + dp[start][i - 1];
                    }else 
                        v = i + Math.max(dp[start][i - 1], dp[i + 1][start + len - 1]);
                    
                    min = Math.min(min, v);
                }
                dp[start][start + len - 1] = min;
            }
        }
        
        return dp[1][n];
    }
}
进一步优化: [start, (start + end) / 2] 永远比 [(start + end) / 2, end]小,所以只需计算后半部分。BigO不变

475. Heaters

475Heaters
Winter is coming! Your first job during the contest is to design a standard heater with fixed warm radius to warm all the houses.
Now, you are given positions of houses and heaters on a horizontal line, find out minimum radius of heaters so that all houses could be covered by those heaters.
So, your input will be the positions of houses and heaters seperately, and your expected output will be the minimum radius standard of heaters.
Note:
  1. Numbers of houses and heaters you are given are non-negative and will not exceed 25000.
  2. Positions of houses and heaters you are given are non-negative and will not exceed 10^9.
  3. As long as a house is in the heaters' warm radius range, it can be warmed.
  4. All the heaters follow your radius standard and the warm radius will the same.
Example 1:
Input: [1,2,3],[2]
Output: 1
Explanation: The only heater was placed in the position 2, and if we use the radius 1 standard, then all the houses can be warmed.
Example 2:
Input: [1,2,3,4],[1,4]
Output: 1
Explanation: The two heater was placed in the position 1 and 4. We need to use radius 1 standard, then all the houses can be warmed.
---------------------
对每一个house,2分查找距离它最近的heater。然后所有house里面取最大的距离返回
O((m + n) * lg n), m是house的长度,n是heater的长度

class Solution {
    public int findRadius(int[] houses, int[] heaters) {
        Arrays.sort(heaters);
        int max = 0;
        for (int house : houses) {
            max = Math.max(max, findClosest(house, heaters));
        }
        
        return max;
    }
    
    private int findClosest(int target, int[] arr) {
        int min = Integer.MAX_VALUE;
        int left = 0, right = arr.length - 1;

        while (left <= right) {
            
            int mid = (left + right) / 2;
            min = Math.min(Math.abs(arr[mid] - target), min);
            min = Math.min(Math.abs(arr[left] - target), min);
            min = Math.min(Math.abs(arr[right] - target), min);
            
            if (arr[mid] == target) return 0;
            else if (arr[mid] < target) {
                left = mid + 1;
            }else {
                right = mid - 1;
            }
        }

        return min;
    }
}

Saturday, November 17, 2018

528. Random Pick with Weight

528Random Pick with Weight
Given an array w of positive integers, where w[i] describes the weight of index i, write a function pickIndex which randomly picks an index in proportion to its weight.
Note:
  1. 1 <= w.length <= 10000
  2. 1 <= w[i] <= 10^5
  3. pickIndex will be called at most 10000 times.
Example 1:
Input: 
["Solution","pickIndex"]
[[[1]],[]]
Output: [null,0]
Example 2:
Input: 
["Solution","pickIndex","pickIndex","pickIndex","pickIndex","pickIndex"]
[[[1,3]],[],[],[],[],[]]
Output: [null,0,1,1,1,0]
Explanation of Input Syntax:
The input is two lists: the subroutines called and their arguments. Solution's constructor has one argument, the array wpickIndex has no arguments. Arguments are always wrapped with a list, even if there aren't any.
---------------------------
Solution #1
pickIndex O(n) time
class Solution {

    private double calls;
    private int[] count;
    private double totalWeight;
    private Random rand;
    private int[] w;
    
    public Solution(int[] w) {
        count = new int[w.length];
        calls = 0;
        rand = new Random();
        this.w = w;
        for (int i : w) totalWeight += (double)i;
    }
    
    public int pickIndex() {
        calls++;
        int next = rand.nextInt(w.length);
        
        while (count[next] / calls > w[next] / totalWeight) {
            next = rand.nextInt(w.length);
        }
        
        count[next]++;
        return next;
    }
}

/**
 * Your Solution object will be instantiated and called as such:
 * Solution obj = new Solution(w);
 * int param_1 = obj.pickIndex();
 */

Solution #2
与Solution #1用array的大小当做random范围不同,这里我们用整个array的totalWeight当做random的范围,然后用accumulative sum来划分原来的weight array。然后用二分法找到落入该区间的所属的index
O(lgN)
class Solution {
    
    private int[] sums;
    private Random rand = new Random();
    private int range;
    private int n;
    
    public Solution(int[] w) {
        
        n = w.length;
        sums = new int[n];
        sums[0] = w[0] - 1;
        
        for (int i = 1; i < n; i++) {
            sums[i] = sums[i - 1] + w[i];
        }
        
        range = sums[n - 1];
    }
    
    public int pickIndex() {
        int target = rand.nextInt(range + 1);
        int left = 0, right = n - 1;
        
        while (left < right) {
            int mid = (left + right) / 2;
            if (sums[mid] == target) {
                return mid;
            }else if (sums[mid] > target) {
                right = mid;
            }else {
                left = mid + 1;
            }
        }
        
        return left;
    }
}

/**
 * Your Solution object will be instantiated and called as such:
 * Solution obj = new Solution(w);
 * int param_1 = obj.pickIndex();
 */

Sunday, October 7, 2018

658. Find K Closest Elements

658Find K Closest Elements
Given a sorted array, two integers k and x, find the k closest elements to x in the array. The result should also be sorted in ascending order. If there is a tie, the smaller elements are always preferred.
Example 1:
Input: [1,2,3,4,5], k=4, x=3
Output: [1,2,3,4]
Example 2:
Input: [1,2,3,4,5], k=4, x=-1
Output: [1,2,3,4]
Note:
  1. The value k is positive and will always be smaller than the length of the sorted array.
  2. Length of the given array is positive and will not exceed 104
  3. Absolute value of elements in the array and x will not exceed 104
----------------
Solution #1, O(logN + K)
class Solution {
    public List<Integer> findClosestElements(int[] arr, int k, int x) {
        int left = findClosest(arr, x);
        int right = left + 1;
        int n = arr.length;
        if (left == -1) {
            right = k;
        }else if (left == n) {
            right = n;
            left = n - k - 1;
        }else {
            while (k > 0) {
                if (left >= 0 && right < n) {
                    if (x - arr[left] > arr[right] - x) {
                        right++;
                    }else {
                        left--;
                    }
                }else if (left >= 0) {
                    left--;
                }else {
                    right++;
                }

                k--;
            }
        }
        left++;
        right--;
        
        List<Integer> rt = new ArrayList<>();
        for (int i = left; i <= right; i++) {
            rt.add(arr[i]);
        }
        
        return rt;
    }
    
    private int findClosest(int[] arr, int x) {
        int left = 0, right = arr.length - 1;
        
        while (left <= right) {
            int mid = (left + right) / 2;
            if (mid < arr.length - 1 && arr[mid] <= x && arr[mid + 1] > x) return mid;
            if (arr[mid] > x) {
                right = mid - 1;
            }else {
                left = mid + 1;
            }
        }
        
        return left;
    }
}

Solution #2, O(logN + K),ref:https://leetcode.com/problems/find-k-closest-elements/discuss/106419/O(log-n)-Java-1-line-O(log(n)-+-k)-Ruby
二分查找subarray的起点,用反证法可以证明此算法的正确性
class Solution {
    public List<Integer> findClosestElements(int[] arr, int k, int x) {
        int left = 0, right = arr.length - k;
        
        while (left < right) {
            int mid = (left + right) / 2;
            if (x - arr[mid] <= arr[mid + k] - x) {
                right = mid;
            }else {
                left = mid + 1;
            }
        }
        
        List<Integer> rt = new ArrayList<>();
        for (int i = 0; i < k; i++) {
            rt.add(arr[left + i]);
        }
        
        return rt;
    }
}

Saturday, October 31, 2015

Day 132, #287 #290 #291 #292 #296 Find the Duplicate Number, Word Pattern, Word Pattern II, Nim Game, Best Meeting Point

Find the Duplicate Number
 Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.
Note:


  1. You must not modify the array (assume the array is read only).
  2. You must use only constant, O(1) extra space.
  3. Your runtime complexity should be less than O(n2).
  4. There is only one duplicate number in the array, but it could be repeated more than once.
-----------------------------------------------------------------------
Sol #1: 因为数字的范围是1 - n, 在范围内取一个值,遍历所给的数组,记下所有比这个值小的个数,进行对比。取值的方法用binary search
O(nlgn)
class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int n = nums.size() - 1;
        int low = 1, high = n;
        
        while (low < high) {
            int mid = (low + high) / 2;
            int count = 0;
            for (int i = 0; i <= n; i++) {
                if (nums[i] <= mid) {
                    count++;
                }
            }
            
            if (count > mid) {
                high = mid;
            }else {
                low = mid + 1;
            }
            if (low == high) return low;
        }
        
    }
};
O(n)
ref:  http://keithschwarz.com/interesting/code/?dir=find-duplicate
class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int n = nums.size();
        int slow = n, fast = n;
        
        while (true) {
            fast = nums[nums[fast - 1] - 1];
            slow = nums[slow - 1];
            if (slow == fast) break;
        }
        
        slow = n;
        while (slow != fast) {
            slow = nums[slow - 1];
            fast = nums[fast - 1];
        }
        
        return slow;
    }
};

Word Pattern
Given a pattern and a string str, find if str follows the same pattern.
Here follow means a full match, such that there is a bijection between a letter in pattern and a non-empty word in str.
Examples:
  1. pattern = "abba", str = "dog cat cat dog" should return true.
  2. pattern = "abba", str = "dog cat cat fish" should return false.
  3. pattern = "aaaa", str = "dog cat cat dog" should return false.
  4. pattern = "abba", str = "dog dog dog dog" should return false.
Notes:
You may assume pattern contains only lowercase letters, and str contains lowercase letters separated by a single space.
--------------------------------------------------
2个hashmap 互相对应
class Solution {
public:
    string getWord(string str, int &index) {
        string rt = "";
        for (; index < str.length(); index++) {
            if (isalpha(str[index])) {
                rt += str[index];
            }else break;
        }
        index++;
        return rt;
    }

    bool wordPattern(string pattern, string str) {
        unordered_map<char,string> pToS;
        unordered_map<string,char> sToP;
        int index = 0;
        
        for (int i = 0; i < pattern.length(); i++) {
            if (index == str.length()) return false;
            string word = getWord(str,index);
            if (pToS.find(pattern[i]) == pToS.end()) {
                pToS[pattern[i]] = word;
            }else if (word != pToS[pattern[i]]) return false;
            
            if (sToP.find(word) == sToP.end()) {
                sToP[word] = pattern[i];
            }else if (sToP[word] != pattern[i]) return false;
        }
        
        return index == str.length() + 1;
    }
};

Word Pattern II
Given a pattern and a string str, find if str follows the same pattern.
Here follow means a full match, such that there is a bijection between a letter in pattern and a non-empty substring in str.
Examples:
  1. pattern = "abab", str = "redblueredblue" should return true.
  2. pattern = "aaaa", str = "asdasdasdasd" should return true.
  3. pattern = "aabb", str = "xyzabcxzyabc" should return false.
Notes:
You may assume both pattern and str contains only lowercase letters.
-------------------------------------------------------
back tracking
对一个pattern[i], 试遍每一种可能
class Solution {
public:
    bool helper(string pattern, int i, string str, int is, unordered_map<char,string> &ptos, unordered_map<string,char> &stop) {
        if (i == pattern.length() && is == str.length()) return true;
        if (i == pattern.length() || is == str.length()) return false;
        
        if (ptos.find(pattern[i]) != ptos.end()) {
            if (ptos[pattern[i]] == str.substr(is,ptos[pattern[i]].length())) {
                return helper(pattern,i + 1, str, is + ptos[pattern[i]].length(),ptos,stop);
            }
            return false;
        }
        
        for (int j = is; j < str.length(); j++) {
            string word = str.substr(is,j - is + 1);
            if (stop.find(word) != stop.end()) continue;
            
            ptos[pattern[i]] = word;
            stop[word] = pattern[i];
            if (helper(pattern, i + 1, str, j + 1, ptos,stop)) return true;
            ptos.erase(pattern[i]);
            stop.erase(word);
        }
        
        return false;
    }

    bool wordPatternMatch(string pattern, string str) {
        unordered_map<char,string> ptos;
        unordered_map<string,char> stop;
        
        return helper(pattern,0,str,0,ptos,stop);
    }
};

Nim Game
 You are playing the following Nim Game with your friend: There is a heap of stones on the table, each time one of you take turns to remove 1 to 3 stones. The one who removes the last stone will be the winner. You will take the first turn to remove the stones.
Both of you are very clever and have optimal strategies for the game. Write a function to determine whether you can win the game given the number of stones in the heap.
For example, if there are 4 stones in the heap, then you will never win the game: no matter 1, 2, or 3 stones you remove, the last stone will always be removed by your friend.
Hint:
  1. If there are 5 stones in the heap, could you figure out a way to remove the stones such that you will always be the winner? 
---------------------------------------
可递归,可DP,但是以下为最简
class Solution {
public:
    bool canWinNim(int n) {
        return n % 4;
    }
};

Best Meeting Point
A group of two or more people wants to meet and minimize the total travel distance. You are given a 2D grid of values 0 or 1, where each 1 marks the home of someone in the group. The distance is calculated using Manhattan Distance, where distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|.
For example, given three people living at (0,0)(0,4), and (2,2):
1 - 0 - 0 - 0 - 1
|   |   |   |   |
0 - 0 - 0 - 0 - 0
|   |   |   |   |
0 - 0 - 1 - 0 - 0
The point (0,2) is an ideal meeting point, as the total travel distance of 2+2+2=6 is minimal. So return 6.
Hint:
  1. Try to solve it in one dimension first. How can this solution apply to the two dimension case?
--------------------------------------------------------------
O(m*n*log(m*n) )
class Solution {
public:
    int minTotalDistance(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();
        vector<int> I,J;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1) {
                    I.push_back(i);
                    J.push_back(j);
                }
            }
        }
        
        return getDis(I) + getDis(J);
    }
    
    int getDis(vector<int> &num) {
        int rt = 0, left = 0, right = num.size() - 1;
        sort(num.begin(), num.end());
        
        while (left < right) {
            rt += num[right] - num[left];
            right--;
            left++;
        }
        
        return rt;
    }
};

O(mn)
class Solution {
public:
    int minTotalDistance(vector>& grid) {
        int m = grid.size(), n = grid[0].size();
        vector I,J;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1) {
                    I.push_back(i);
                }
            }
        }
        
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[j][i] == 1) {
                    J.push_back(i);
                }
            }
        }
        
        return getDis(I) + getDis(J);
    }
    
    int getDis(vector &num) {
        int rt = 0, left = 0, right = num.size() - 1;
        
        while (left < right) {
            rt += num[right] - num[left];
            right--;
            left++;
        }
        
        return rt;
    }
};

Thursday, July 23, 2015

Day 118, 240 Search a 2D Matrix II, Majority Number III

Search a 2D Matrix II
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:
  • Integers in each row are sorted in ascending from left to right.
  • Integers in each column are sorted in ascending from top to bottom.
For example,
Consider the following matrix:
[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]
Given target = 5, return true.
Given target = 20, return false.

---------------------------------------------------------------------------
REFhttp://articles.leetcode.com/2010/10/searching-2d-sorted-matrix-part-ii.html
O(n)
class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int m = matrix.size();
        int n = matrix[0].size();
        
        int row = 0, col = n - 1;
        while (row < m && col >= 0) {
            if (matrix[row][col] == target) return true;
            if (matrix[row][col] > target) {
                col--;
            }else {
                row++;
            }
        }
        
        return false;
    }
};

O((lgn)^2)
class Solution {
public:
    bool helper(vector<vector<int>>& matrix, int target,int rowStart,int rowEnd,int colStart,int colEnd) {
        if (rowStart > rowEnd || colStart > colEnd) {
            return false;
        }
        
        int row = (rowStart + rowEnd) / 2;
        int left = colStart,right = colEnd;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (matrix[row][mid] == target) return true;
            if (matrix[row][mid] < target) {
                left = mid + 1;
            }else {
                right = mid - 1;
            }
        }
        
        return helper(matrix,target,rowStart,row - 1,right + 1,colEnd) 
                || helper(matrix,target,row + 1,rowEnd,colStart,right);
    }

    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int m = matrix.size();
        if (m == 0) return false;
        int n = matrix[0].size();
        
        return helper(matrix,target,0,m - 1,0,n - 1);
    }
};

Majority Number III
Given an array of integers and a number k, the majority number is the number that occurs more than 1/k of the size of the array.
Find it.
Have you met this question in a real interview? 
Yes
Example
Given [3,1,2,3,2,3,3,4,4,4] and k=3, return 3.
Note
There is only one majority number in the array.

Challenge
O(n) time and O(k) extra space
-------------------------------------------
用hash map来记录value跟count, 原理跟1、2相同
class Solution {
public:
    /**
     * @param nums: A list of integers
     * @param k: As described
     * @return: The majority number
     */
    int majorityNumber(vector<int> nums, int k) {
        // write your code here
        unordered_map<int,int> dic;
        
        for (int i = 0; i < nums.size(); i++) {
            if (dic.find(nums[i]) == dic.end()) {
                dic.insert(make_pair(nums[i],1));
            }else {
                dic[nums[i]]++;
            }
            
            if (dic.size() == k) {
             vector<int> t;
             for (auto kv : dic) {
              t.push_back(kv.first);
             }
             
                for (int i : t) {
                    dic[i]--;
                    if (dic[i] == 0) {
                        dic.erase(i);
                    }
                }
            }
        }
        
        unordered_map<int,int> left;
        int maxCount = 0, maxVal = 0;
        for (int i = 0; i < nums.size(); i++) {
            if (dic.find(nums[i]) != dic.end()) {
                if (left.find(nums[i]) == left.end()) {
                    left[nums[i]] = 1;
                }else {
                    left[nums[i]]++;
                }
                if (maxCount < left[nums[i]]) {
                    maxCount = left[nums[i]];
                    maxVal = nums[i];
                }
            }
        }
        
        return maxVal;
    }
};

Sunday, June 14, 2015

Day 107, ##, Minimum Size Subarray Sum, Course Schedule II

Minimum Size Subarray Sum
Given an array of n positive integers and a positive integer s, find the minimal length of a subarray of which the sum ≥ s. If there isn't one, return 0 instead.
For example, given the array [2,3,1,2,4,3] and s = 7,
the subarray [4,3] has the minimal length under the problem constraint.
More practice:
If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log n).
-------------------------------------------------------
Sliding window, O(n)

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        if (nums.size() == 0) return 0;
        int minLen = INT_MAX;
        int right = 0, left = 0;
        
        int sum = nums[right];
        while (right < nums.size()) {
            if (sum < s) {
                right++;
                sum += nums[right];
            }else {
                minLen = min(right - left + 1, minLen);
                sum -= nums[left];
                left++;
            }
        }
        
        if (minLen == INT_MAX) return 0;
        return minLen;
    }
};
O(NlogN),
sums[i]计算了nums[0 : i + 1]的连续值,所以sums内的值是递增,由此可以用binary search
所求的最短subarray就是计算 sums[i] + s >= sums[j], j取[1: ]
注意各variable的取值
binary()返回的值可能会等于 sums.size(),


class Solution {
public:
    int binary(int s, vector<int> &sums, int left) {
        int right = sums.size() - 1;
        int minLen = INT_MAX;
        int sum = 0;
        
        while (left <= right) {
            int mid = left + (right - left) / 2; 
            if (sums[mid] >= s) {
                right = mid - 1;
            }else {
                left = mid + 1;
            }
        }
        
        return left;
    }

    int minSubArrayLen(int s, vector<int>& nums) {
        if (nums.size() == 0) return 0;
        int minLen = INT_MAX;
        
        vector<int> sums(nums.size() + 1,0);
        for (int i = 1; i <= nums.size(); i++) {
            sums[i] = sums[i - 1] + nums[i - 1];
        }
        
        for (int i = 0; i < nums.size(); i++) {
            int end = binary(s + sums[i - 1],sums,i);
            if (end == sums.size()) break;
            minLen = min(end - i + 1, minLen);
        }
        
        if (minLen == INT_MAX) return 0;
        return minLen;
    }
};

Java O(n)版本
class Solution {
    public int minSubArrayLen(int s, int[] nums) {
        int n = nums.length;
        int start = 0;
        int minLen = n + 1;
        int sum = 0;
        
        for (int i = 0; i < n; i++) {
            sum += nums[i];
            
            while (sum >= s) {
                minLen = Math.min(minLen, i - start + 1);
                sum -= nums[start];
                start++;
            }
        }
        
        return minLen > n ? 0 : minLen;
    }
}
Course Schedule II
There are a total of n courses you have to take, labeled from 0 to n - 1.
Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]
Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses.
There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array.
For example:
2, [[1,0]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0. So the correct course order is [0,1]
4, [[1,0],[2,0],[3,1],[3,2]]
There are a total of 4 courses to take. To take course 3 you should have finished both courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. So one correct course order is [0,1,2,3]. Another correct ordering is[0,2,1,3].
Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
Hints:
  1. This problem is equivalent to finding the topological order in a directed graph. If a cycle exists, no topological ordering exists and therefore it will be impossible to take all courses.
  2. Topological Sort via DFS - A great video tutorial (21 minutes) on Coursera explaining the basic concepts of Topological Sort.
  3. Topological sort could also be done via BFS.
-----------------------------------------------------
topological sort, 考虑cycle问题
DFS
class Solution {
public:
    bool dfs(vector<vector<int>> &edges,int course,vector<int> &visit,vector<int> &path) {
        if (visit[course] == -1) return false;
        if (visit[course] == 1) return true;
        visit[course] = -1;
        
        for (int i = 0; i < edges[course].size(); i++) {
            if (!dfs(edges,edges[course][i],visit,path)) return false;
        }
        path.push_back(course);
        visit[course] = 1;
        return true;
    }

    vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<vector<int>> edges(numCourses,vector<int>());
        vector<int> path;
        vector<int> visit(numCourses,0);    
        
        for (int i = 0; i < prerequisites.size(); i++) {
            edges[prerequisites[i].second].push_back(prerequisites[i].first);
        }
        for (int i = 0; i < numCourses; i++) {
            if (!dfs(edges,i,visit,path)) {
                vector<int> rt;
                return rt;
            }
        }
        reverse(path.begin(),path.end());
        return path;
    }
};
BFS
ref: https://en.wikipedia.org/wiki/Topological_sorting#Algorithms
class Solution {
public:
    vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<vector<int> > edges(numCourses);
        vector<int> order;
        vector<int> inDegree(numCourses,0);
        queue<int> que;
        
        for (int i = 0; i < prerequisites.size(); i++) {
            edges[prerequisites[i].second].push_back(prerequisites[i].first);
            inDegree[prerequisites[i].first]++;
        }
        
        for (int i = 0; i < numCourses; i++) {
            if (inDegree[i] == 0) {
                que.push(i);
            }
        }
        
        while (!que.empty()) {
            int current = que.front();
            que.pop();
            order.push_back(current)
            ;
            for (int i = 0; i < edges[current].size(); i++) {
                int neighbor = edges[current][i];
                inDegree[neighbor]--;
                if (inDegree[neighbor] == 0) {
                    que.push(neighbor);
                }
            }
        }
        
        for (int i = 0; i < numCourses; i++) {
            if (inDegree[i] != 0) {
                order = vector<int>();
                return order;
            }
        }
        
        return order;
    }
};

Thursday, January 22, 2015

Day 94, ##, Find Peak Element

Find Peak Element

A peak element is an element that is greater than its neighbors.
Given an input array where num[i] ≠ num[i+1], find a peak element and return its index.
The array may contain multiple peaks, in that case return the index to any one of the peaks is fine.
You may imagine that num[-1] = num[n] = -∞.
For example, in array [1, 2, 3, 1], 3 is a peak element and your function should return the index number 2.

------------------------------------------------------------

class Solution {
public:
    int findPeakElement(const vector<int> &num) {
        if (num[0] > num[1]) return 0;
        if (num[num.size() - 1] > num[num.size() - 2]) return num.size() - 1; 
        
        int left = 1, right = num.size() - 2;
        while (left <= right) {
            int mid = right + (left - right) / 2;
            if (num[mid] > num[mid - 1] && num[mid] > num[mid + 1]) {
                return mid;
            }else if (num[mid] > num[mid + 1]) {
                right = mid - 1;
            }else {
                left = mid + 1;
            }
        }
        
        return num.size() - 1;
    }
};

Java, updated on Oct-10th-2018
1. left < right 保证了mid + 1时不用对mid做boundry check
2. right = mid, 因为此时[mid] > [mid + 1], mid还算是一个candidate
3. ToDo: 二分法的一种写法是不设base case,然后由while里的条件来结束,最后返回left。https://shibaili.blogspot.com/2018/10/658-find-k-closest-elements.html 第2个方法用了类似的方法

class Solution {
    public int findPeakElement(int[] nums) {
        int left = 0, right = nums.length - 1;
        
        while (left < right) {
            int mid = (left + right) / 2;
            if (nums[mid] < nums[mid + 1]) {
                left = mid + 1;
            }else {
                right = mid;
            }
        }
        
        return left;
    }
}

Tuesday, December 16, 2014

Day 81, #81, Search in Rotated Sorted Array II

Search in Rotated Sorted Array II

Follow up for "Search in Rotated Sorted Array":
What if duplicates are allowed?
Would this affect the run-time complexity? How and why?
Write a function to determine if a given target is in the array.
--------------------------------------------------------------------------
与I同样的思路,不同点是增加了1个if判断来解决重复的问题
重复的情况#1: start,mid,end 3处都相等,如111111111111112111。此时左右两半都需要检测,worst cast O(n)
重复的情况#2:仅start或者end跟mid相等,如4444123,此时原有代码也可解决

class Solution {
public:
    bool searchInRotated(int A[], int start, int end, int target) {
        if (start > end) {
            return false;
        }
        int mid = (start + end) / 2;
        if (A[mid] == target) {
            return true;
        }
        
        // ------ to handle duplicates ---- 
        if (A[start] == A[mid] && A[start] == A[end]) {
            return searchInRotated(A,start,mid - 1,target) || searchInRotated(A,mid + 1,end,target);
        }
        
        if (A[start] <= A[mid]) {
            if (A[start] <= target && target <= A[mid]) {
                return searchInRotated(A,start,mid - 1,target);
            }else {
                return searchInRotated(A,mid + 1,end,target);
            }
        }else {
            if (A[mid] <= target && target <= A[end]) {
                return searchInRotated(A,mid + 1,end,target);
            }else {
                return searchInRotated(A,start,mid - 1,target);
            }
        }
        
    }

    bool search(int A[], int n, int target) {
        return searchInRotated(A,0,n - 1,target);
    }
};
Solution #2, iterative(to do)

Friday, November 28, 2014

Day 75, #5, Median of Two Sorted Arrays

Median of Two Sorted Arrays
There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

------------------------------------------------------------------------------------------
a special case of find kth smallest
reference:
http://leetcode.com/2011/01/find-k-th-smallest-element-in-union-of.html
http://www.programcreek.com/2012/12/leetcode-median-of-two-sorted-arrays-java/
http://blog.csdn.net/yutianzuijin/article/details/11499917
un-solved:
#1 how to determine k's value: int kA = k * lenA / (lenB + lenA)
#2 why is this inclusive: endA = kA
class Solution {
public:
    double findKth (int A[], int startA,int endA, int B[], int startB,int endB, int k) {
        int lenA = endA - startA + 1;
        int lenB = endB - startB + 1;
        if (lenA == 0) {
            return B[startB + k];
        }
        if (lenB == 0) {
            return A[startA + k];
        }
        
        if (k == 0) {
            return min(A[startA],B[startB]);
        }
        
        int kA = k * lenA / (lenB + lenA); // ???
        int kB = k - kA - 1;
        kA += startA;
        kB += startB;
        
        if (A[kA] == B[kB]) {
            return A[kA];
        }
        
        if (A[kA] > B[kB]) {
            k = k - (kB - startB + 1);
            endA = kA; // inclusive, why?
            startB = kB + 1;
            
        }else {
            k = k - (kA - startA + 1);
            startA = kA + 1; 
            endB = kB; // inclusive
        }
        
        return findKth(A,startA,endA,B,startB,endB,k);
    }

    double findMedianSortedArrays(int A[], int m, int B[], int n) {
        if ((m + n) % 2 == 1) {
            return findKth(A,0,m - 1,B,0,n - 1, (m + n) / 2);
        }else {
            return (findKth(A,0,m - 1,B,0,n - 1, (m + n) / 2) + findKth(A,0,m - 1,B,0,n - 1, (m + n) / 2 - 1)) / 2.0;
        }
    }
};
Solution #2, reference:  http://www2.myoops.org/course_material/mit/NR/rdonlyres/Electrical-Engineering-and-Computer-Science/6-046JFall-2005/30C68118-E436-4FE3-8C79-6BAFBB07D935/0/ps9sol.pdf
如果A[i]是中位数,则A[i]比A里i 个数都大, 比B里(m+n)/2 - i 个数都大
j = (m+n)/2 - i - 1
B[j] < A[i] < B[j + 1]
反之,A在B[j]和B[j + 1]的左侧或者右侧
class Solution {
public:
    double findMedian (int A[],int B[],int m,int n,int left,int right) {
        if (left > right) {
            return findMedian(B,A,n,m,max(0,(m+n)/2 - m),min(n,(m+n)/2));
        }
        
        int i = (left + right) / 2;
        int j = (m + n) / 2 - i - 1;
        
        if (j >= 0 && A[i] < B[j]) {
            return findMedian(A,B,m,n,i + 1, right);
        }
        
        if (j < n - 1 && A[i] > B[j + 1]) {
            return findMedian(A,B,m,n,left,i - 1);
        }
        
        if ((m + n) % 2 == 1) {
            return A[i];
        }
        if (i > 0) {
            return (A[i] + max(B[j],A[i - 1])) / 2.0;
        }
        return (A[i] + B[j]) / 2.0;
        
    }

    double findMedianSortedArrays(int A[], int m, int B[], int n) {
        if (m > n) {
            return findMedian(A,B,m,n,max(0,(m+n)/2 - n),min(m,(m+n)/2));
        }
        return findMedian(B,A,n,m,max(0,(m+n)/2 - m),min(n,(m+n)/2));
    }
};

Another one, takes half of k at each call, key us (k + 1) / 2
#1 当A里的元素不足 k / 2 个时,可以砍掉B的前 k / 2
#2 当 A[k/2] < B[k/2], 可以砍掉A的前 k / 2
以上都可以用反证法证明

k为0-based

  1. return B[BStart + k]意思为返回第 k + 1(1-based)小的elem
  2. AK = (k + 1) / 2, 为个数,所以 k 需要 + 1
  3. AStart + AK - 1, 同样道理,AK是个数(1-based),需要转换为 0-based
  4. return findKth(,....AStart + AK), AK是要被砍掉的个数,所以不用 - 1
base condition以下,k和AK,BK不可能为0,所以需要 - 1,不然AStart永远取不到


http://www.ninechapter.com/solutions/median-of-two-sorted-arrays/
class Solution {
public:
    double findKth(int A[],int m, int AStart, int B[], int n, int BStart, int k) {
        if (AStart == m) return B[BStart + k];
        if (BStart == n) return A[AStart + k];
        
        if (k == 0) return min(A[AStart],B[BStart]); 
        
        int AKey = INT_MAX;
        int BKey = INT_MAX;
        int AK = (k + 1) / 2;
        int BK = (k + 1) / 2;
        
        if (AStart + AK - 1 < m) {
            AKey = A[AStart + AK - 1];
        }
        if (BStart + BK - 1 < n) {
            BKey = B[BStart + BK - 1];
        }
        
        if (AKey < BKey) {
            return findKth(A,m,AStart + AK,B,n,BStart,k - AK);
        }else {
            return findKth(A,m,AStart,B,n,BStart + BK,k - BK);
        }
        
    }

    double findMedianSortedArrays(int A[], int m, int B[], int n) {
        int k = n + m;
        if (k % 2 == 0) {
            return (findKth(A,m, 0, B,n, 0, k / 2 - 1) + findKth(A,m,0, B, n, 0, k / 2)) / 2.0 ;
        } else {
            return findKth(A,m,0, B, n, 0, k / 2);
        }
    }
};

Sunday, December 22, 2013

Day 62, #68, #69, Text Justification, Sqrt(x)

Text Justification
Given an array of words and a length L, format the text such that each line has exactly L characters and is fully (left and right) justified.
You should pack your words in a greedy approach; that is, pack as many words as you can in each line. Pad extra spaces ' ' when necessary so that each line has exactly L characters.
Extra spaces between words should be distributed as evenly as possible. If the number of spaces on a line do not divide evenly between words, the empty slots on the left will be assigned more spaces than the slots on the right.
For the last line of text, it should be left justified and no extra space is inserted between words.
For example,
words: ["This", "is", "an", "example", "of", "text", "justification."]
L: 16.
Return the formatted lines as:

[
   "This    is    an",
   "example  of text",
   "justification.  "
]
Note: Each word is guaranteed not to exceed L in length.
Corner Cases:
  • A line other than the last line might contain only one word. What should you do in this case?
    In this case, that line should be left-justified.
--------------------------------
This is one of the most muthaFking types of questions. It makes people suicidal until it  passes the OJ.
class Solution {
public:
    vector<string> fullJustify(vector<string> &words, int L) {
        int used = 0;
        vector<string> ret;
        vector<string> temp;
        if (L == 0) {
            ret.push_back("");
            return ret;
        }
        
        bool flag =false;
        for (int i = 0; i < words.size(); i++) {
            // always have one element in the temp. ease the pain
            if (!flag) {
                temp.clear();
                used = 0;
                used = words[i].length();
                temp.push_back(words[i]);
                flag = true;
            }else {
                // keep feeding the temp
                if (words[i].length() + 1 + used <= L) {
                    temp.push_back(" " + words[i]);
                    used += 1 + words[i].length();
                }
                
                // if used + current word's length is larger than L
                // clear temp, form the line and push it to ret
                else {
                    i--; // back by one step
                    flag = false;
                    if (temp.size() == 1) {
                        string str = temp[0];
                        for (int j = 0; j < L - used; j++) {
                            str += " ";
                        }
                        ret.push_back(str);
                        continue;
                    }
                    
                    // calculate extra space between words 
                    int spaceCount = (L - used) / (temp.size() - 1);
                    int extraSpace = (L - used) % (temp.size() - 1);
                    string space = "";
                    for (int j = 0; j < spaceCount; j++) {
                        space += " ";
                    }
                    
                    string str = temp[0];
                    for (int j = 1; j < temp.size(); j++) {
                        if (extraSpace > 0) {
                            str += " ";
                            extraSpace--;
                        }
                        str += space + temp[j];
                    }
                    ret.push_back(str);
                }
            }
        }
        
        // dealing with the last line
        if (flag) {
            string str = temp[0];
            for (int i = 1; i < temp.size(); i++) {
                str += temp[i];
            }
            for (int i = used; i < L; i++) {
                str += " ";
            }
            ret.push_back(str);
        }
        
        return ret;
    }
};
Sqrt(x)
Implement int sqrt(int x).
Compute and return the square root of x.
--------------------------------------------------
Solution#1, binary search
why always return right in the end??
A: Inorder to break out the loop, we either have sq == x or left > right, for this Sqrt(x) method, we need to return the lower bound(ex. input is 250, return 15, not 16)
class Solution {
public:
    int sqrt(int x) {
        long long left = 0;
        long long right = x /2 + 1;
        while (left <= right) {
            long long mid = (left + right) / 2;
            long long sq = mid * mid;
            if (sq == x) {
                return mid;
            }
            if (sq < x) {
                left = mid + 1;
            }else {
                right = mid - 1;
            }
        }
        return right; // why always return right
    }
};
Solution#2
Newton's method
Update on Jan-23-2015 
could be if (fabs(i - j) < 0.000001) break;
class Solution {
public:
    int sqrt(int x) {
        if (x == 0) return 0;
        double i = 1.0;
        double j = 1;
        while (true) {
            j = (i + x / i) / 2.0;
            if (i == j) break;
            i = j;
        }
        
        return (int)j;
    }
};