Showing posts with label divide_conquer. Show all posts
Showing posts with label divide_conquer. Show all posts

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;
    }
};

Friday, July 17, 2015

Coursera - Algorithms: Design and Analysis, Part 1

Week 1 - Question 1 
Download the text file here. (Right click and save link as) This file contains all of the 100,000 integers between 1 and 100,000 (inclusive) in some order, with no integer repeated. Your task is to compute the number of inversions in the file given, where the ith row of the file indicates the ith entry of an array. Because of the large size of this array, you should implement the fast divide-and-conquer algorithm covered in the video lectures. The numeric answer for the given input file should be typed in the space below. So if your answer is 1198233847, then just type 1198233847 in the space provided without any space / commas / any other punctuation marks. You can make up to 5 attempts, and we'll use the best one for grading. (We do not require you to submit your code, so feel free to use any programming language you want --- just type the final numeric answer in the following space.) [TIP: before submitting, first test the correctness of your program on some small test files or your own devising. Then post your best test cases to the discussion forums to help your fellow students!]

count inversion, 基本的merge sort嵌入count
vector<int> merge(vector<int> p1,vector<int> p2,long long &count) {
    vector<int> rt;
    int i = 0, j = 0;
    while (i < p1.size() && j < p2.size()) {
        if (p1[i] < p2[j]) {
            rt.push_back(p1[i]);
            count += j;
            i++;
        }else {
            rt.push_back(p2[j]);
            count += (p1.size() - i);
            j++;
        }
    }
    
    while (i < p1.size()) {
        rt.push_back(p1[i]);
        i++;
        count += j;
    }
    while (j < p2.size()) {
        rt.push_back(p2[j]);
        j++;
    }
    
    return rt;
}

vector<int> mergeSort(vector<int> &nums,int start, int end,long long &count) {
    if (start == end) {
        vector<int> rt(1,nums[start]);
        return rt;
    }
    int mid = (start + end) / 2;
    vector<int> part1 = mergeSort(nums,start,mid,count);
    vector<int> part2 = mergeSort(nums,mid + 1,end,count);
    return merge(part1,part2,count);
}

long long countInversions(vector<int> &nums) {
    long long count = 0;
    vector<int> v = mergeSort(nums,0,nums.size() - 1,count);
    return count / 2;
}
------------------------------------
closest pair of points
class Point{
public:
    int x;
    int y;
};


bool cmpX(Point &p1, Point &p2) {
    return p1.x < p2.x;
}

bool cmpY(Point &p1, Point &p2) {
    return p1.y < p2.y;
}

float bruteForce(vector<Point> &p, int left, int right) {
    // brubute force when there are lessn than 3 nodes
}

float getDistance(Point p1, Point p2) {
    // distance between two points
}

float split(vector<Point> &p,vector<Point> &q, int mid,int minD) {
    vector<Point> strip;
    for (int i = 0; i < strip.size(); i++) {
        if (fabs(strip[i].x - p[mid].x) < minD) {
            strip.push_back(strip[i]);
        }
    }
 
 // 7 position head in y-coordinates is enough
    for (int i = 0; strip.size() - 1; i++) {
        for (int j = i + 1; j <= i + 7 || j < strip.size()) {
            minD = min(minD,getDistance(strip[i],strip[j]));
        }
    }
 
    return midD;
}

float helper(vector<Point> &p,vector<Point> &q,int left,int right) {
    if (right - left <= 3) {
        return bruteForce(p,left,right);
    }
 
    int mid = (left + right) / 2;
    float minDistance = min(helper(p,left,mid), helper(p,mid,right));
 
    return min(minDistance,split(p,mid,minDistance));
}

float closestPair(vector<Point> &p) {
    sort(p.begin(),p.end(),cmpX);
    vector<int> q = p;
    sort(q.begin(),sortByY.end(),cmpY);
 
    helper(p,q,0,p.size() - 1);
}

-------------------------------------------------------------------------------------
  1. [Posted June 29th] You are given as input an unsorted array of n distinct numbers, where n is a power of 2. Give an algorithm that identifies the second-largest number in the array, and that uses at most n+log2n−2 comparisons. 
  2. [Posted June 29th] You are a given a unimodal array of n distinct elements, meaning that its entries are in increasing order up until its maximum element, after which its elements are in decreasing order. Give an algorithm to compute the maximum element that runs in O(log n) time. 找rotated array里的最大值
  3. [Posted June 29th] You are given a sorted (from smallest to largest) array A of n distinct integers which can be positive, negative, or zero. You want to decide whether or not there is an index i such that A[i] = i. Design the fastest algorithm that you can for solving this problem. 2分取中点,如果i大于A[i], 往右走。如果小,往左走
  4. [Posted June 29th] Give the best upper bound that you can on the solution to the following recurrence: T(1)=1 and T(n)≤T([n−−√])+1 for n>1. (Here [x] denotes the "floor" function, which rounds down to the nearest integer.) 
  5. [Posted June 29th] You are given an n by n grid of distinct numbers. A number is a local minimum if it is smaller than all of its neighbors. (A neighbor of a number is one immediately above, below, to the left, or the right. Most numbers have four neighbors; numbers on the side have three; the four corners have two.) Use the divide-and-conquer algorithm design paradigm to compute a local minimum with only O(n) comparisons between pairs of numbers. (Note: since there are n2 numbers in the input, you cannot afford to look at all of them. Hint: Think about what types of recurrences would give you the desired upper bound.) find peak

--------------------------------------------------------------------------
Week 2
Notes:

Sunday, June 21, 2015

Day 110, ##, The Skyline Problem

The Skyline Problem 
A city's skyline is the outer contour of the silhouette formed by all the buildings in that city when viewed from a distance. Now suppose you are given the locations and height of all the buildings as shown on a cityscape photo (Figure A), write a program to output the skyline formed by these buildings collectively (Figure B).
Buildings Skyline Contour
The geometric information of each building is represented by a triplet of integers [Li, Ri, Hi], where Li and Ri are the x coordinates of the left and right edge of the ith building, respectively, and Hi is its height. It is guaranteed that 0 ≤ Li, Ri ≤ INT_MAX0 < Hi ≤ INT_MAX, and Ri - Li > 0. You may assume all buildings are perfect rectangles grounded on an absolutely flat surface at height 0.
For instance, the dimensions of all buildings in Figure A are recorded as: [ [2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8] ] .
The output is a list of "key points" (red dots in Figure B) in the format of [ [x1,y1], [x2, y2], [x3, y3], ... ] that uniquely defines a skyline. A key point is the left endpoint of a horizontal line segment. Note that the last key point, where the rightmost building ends, is merely used to mark the termination of the skyline, and always has zero height. Also, the ground in between any two adjacent buildings should be considered part of the skyline contour.
For instance, the skyline in Figure B should be represented as:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ].
Notes:
  • The number of buildings in any input list is guaranteed to be in the range [0, 10000].
  • The input list is already sorted in ascending order by the left x position Li.
  • The output list must be sorted by the x position.
  • There must be no consecutive horizontal lines of equal height in the output skyline. For instance, [...[2 3], [4 5], [7 5], [11 5], [12 7]...] is not acceptable; the three lines of height 5 should be merged into one in the final output as such: [...[2 3], [4 5], [12 7], ...]
---------------------------------------------------
Runtime error, C++ vector<> has its maximum size.
Use a heightMap of size INT_MAX
class Solution {
public:
    vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
        vector<int> heightMap(INT_MAX,0);
        for (int i = 0; i < buildings.size(); i++) {
            int left = buildings[i][0];
            int height = buildings[i][1];
            int right = buildings[i][2];
            
            for (int j = left; j < right; j++) {
                heightMap[j] = max(height,heightMap[j]);
            }
        }
        
        vector<pair<int,int> > rt; 
        int preHeight = 0;
        for (int i = 0; i <= INT_MAX; i++) {
            if (preHeight != heightMap[i]) {
                rt.push_back(make_pair(i,heightMap[i]));
            }
            
            preHeight = heightMap[i];
        }
        
        return rt;
    }
};
方法1:http://www.cnblogs.com/easonliu/p/4531020.html
一句话,找线段。将所有点按照x坐标排序,注意当点重复时,将线段左边点排在线段后边点之前。遍历所有点,遇到左点说明遭遇新线段,插入它的高度在heap。遇到右点说明线段终止,从heap删除该高度(线段)。对比当前跟之前的高度,就能确定线段分界点
因为只需要求的是building的轮廓,所以heap_top保留的是当前x坐标下最高的线段

以下为方法1
处理重复点
c++ 中operator方法的写法
priority_queue不提供中间删除操作
用map而不是set,防止当不同线段的头和尾重复时,确保删除正确
class Solution {
public:
    struct cmp {
        bool operator() (const pair<int, int>& p1, const pair<int, int>& p2) {
            if (p1.first == p2.first) {
                return p1.second < p2.second;
            }
            return p1.first < p2.first;
        }
    };

    vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
        vector<pair<int,int> > points, rt;
        for (int i = 0; i < buildings.size(); i++) {
            points.push_back(make_pair(buildings[i][0],-buildings[i][2]));
            points.push_back(make_pair(buildings[i][1],buildings[i][2]));
        }
        sort(points.begin(),points.end(),cmp());
        
        priority_queue<int> heightMap;
        heightMap.push(0); // to handle end of a building
        unordered_map<int,int> deleted;
        int pre = 0;
        for (int i = 0; i < points.size(); i++) {
            // left point
            if (points[i].second < 0) {
                heightMap.push(-points[i].second);
            }else {
                // right point
                deleted[points[i].second]++;
                while (!heightMap.empty() && deleted[heightMap.top()] > 0) {
                    deleted[heightMap.top()]--;
                    heightMap.pop();
                }
            }
            
            int cur = heightMap.top();
            if (cur != pre) {
                rt.push_back(make_pair(points[i].first,cur));
                pre = cur;
            }
        }
        
        return rt;
    }
};

方法2:http://www.geeksforgeeks.org/divide-and-conquer-set-7-the-skyline-problem/
basic divide and conquer, 难度在于细节处理上。注意线段的结束点高度设为0
class Solution {
public:
    vector<pair<int,int>> merge(vector<pair<int,int>> left,vector<pair<int,int>> right) {
        vector<pair<int,int>> rt;
        int h1 = 0, h2 = 0;
        int i = 0, j = 0;
        while (i < left.size() && j < right.size()) {
            int x = 0, h = 0;
            if (left[i].first < right[j].first) {
                x = left[i].first;
                h1 = left[i].second;
                h = max(h1,h2);
                i++;
            }else if (left[i].first > right[j].first){
                x = right[j].first;
                h2 = right[j].second;
                h = max(h1,h2);
                j++;
            }else {
                x = left[i].first;
                h1 = left[i].second;
                h2 = right[j].second;
                h = max(h1,h2);
                i++;
                j++;
            }
            if (rt.size() == 0 || rt.back().second != h) {
                rt.push_back(make_pair(x,h));
            }
        }
        
        rt.insert(rt.end(),left.begin() + i,left.end());
        rt.insert(rt.end(),right.begin() + j,right.end());
        return rt;
    }

    vector<pair<int,int>> divide(vector<vector<int>>& buildings, int left,int right) {
        if (left == right) {
            vector<pair<int,int>> rt;
            rt.push_back(make_pair(buildings[left][0],buildings[left][2]));
            rt.push_back(make_pair(buildings[left][1],0));
            return rt;
        }
        int mid = (left + right) / 2;
        vector<pair<int,int>> leftPart = divide(buildings,left,mid);
        vector<pair<int,int>> rightPart = divide(buildings,mid + 1,right);
        return merge(leftPart,rightPart);
    }
    

    vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
        vector<pair<int, int>> rt;
        if (buildings.size() == 0) return rt;
        return divide(buildings,0,buildings.size() - 1);
    }
};

阅读:https://briangordon.github.io/2014/08/the-skyline-problem.html
Java
class Solution {
    public List<int[]> getSkyline(int[][] buildings) {
        
        List<int[]> points = getSortedPoints(buildings);
        return getSkyline(points);        
    }
    
    private List<int[]> getSkyline(List<int[]> points) {
        PriorityQueue<Integer> que = new PriorityQueue<>((a, b) -> b - a);
        Map<Integer, Integer> map = new HashMap<>();
        List<int[]> rt = new ArrayList<>();
        que.add(0);
        map.put(0, 1);
        
        for (int[] point : points) {
            int x = point[0];
            int height = point[1];
            
            if (height > 0) {
                if (que.peek() < height) {
                    rt.add(new int[]{x, height});
                }
                
                que.add(height);
                map.put(height, map.getOrDefault(height, 0) + 1);
            }else {
                
                map.put(-height, map.get(-height) - 1);
                while (map.get(que.peek()) == 0)  {
                    que.poll();
                }
                
                if (-height > que.peek()) {
                    rt.add(new int[]{x, que.peek()});
                }
                
            }
        }
        
        return rt;
    }
    
    private List<int[]> getSortedPoints(int[][] buildings) {
        List<int[]> points = new ArrayList<>();
        
        for (int[] building : buildings) {
            points.add(new int[]{building[0], building[2]});
            points.add(new int[]{building[1], -building[2]});    
        }
        
        Collections.sort(points, (a, b) -> {
            if (a[0] == b[0]) {
                return b[1] - a[1];
            }
            return a[0] - b[0];
        });
        
        return points;
    }
}