Showing posts with label greedy. Show all posts
Showing posts with label greedy. Show all posts

Friday, November 16, 2018

753. Cracking the Safe

753Cracking the Safe
There is a box protected by a password. The password is n digits, where each letter can be one of the first k digits 0, 1, ..., k-1.
You can keep inputting the password, the password will automatically be matched against the last n digits entered.
For example, assuming the password is "345", I can open it when I type "012345", but I enter a total of 6 digits.
Please return any string of minimum length that is guaranteed to open the box after the entire string is inputted.
Example 1:
Input: n = 1, k = 2
Output: "01"
Note: "10" will be accepted too.
Example 2:
Input: n = 2, k = 2
Output: "00110"
Note: "01100", "10011", "11001" will be accepted too.
Note:
  1. n will be in the range [1, 4].
  2. k will be in the range [1, 10].
  3. k^n will be at most 4096.
----------------
题意是找一个最短的string,这个string得包含所有n长度的排列组合。最优的解是2个排列组合之间只相差一位,如 1234 -> 2345, *234 -> 234*. 解法是把234看作一个结点,12345为这个结点的边,把所有边都遍历一次就可以了
Eulerian path的定义https://en.wikipedia.org/wiki/Eulerian_path
用Hierholzer's algorithm来求path

O(k * k^n) time, Hierholzer's algorithm本来 是O(k^n), 但是以下实现方式每次都对k个边做检查来寻找未走过的边,所以有额外的k消耗
ToDo
class Solution {
    public String crackSafe(int n, int k) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n; i++) {
            sb.append("0");
        }
        
        Set<String> visited = new HashSet<>();
        visited.add(sb.toString());
        dfs(sb, visited, k, n);
        return sb.toString();
    }
    
    private void dfs(StringBuilder sb, Set<String> visited, int k, int n) {
        String node = sb.substring(sb.length() - n + 1);
        for (int i = k - 1; i >= 0; i--) {
            String s = node + Integer.toString(i);
            if (!visited.contains(s)) {
                visited.add(s);
                sb.append(Integer.toString(i));
                dfs(sb, visited, k, n);
            }
        }
    }
}

Monday, November 12, 2018

465. Optimal Account Balancing

465Optimal Account Balancing
A group of friends went on holiday and sometimes lent each other money. For example, Alice paid for Bill's lunch for $10. Then later Chris gave Alice $5 for a taxi ride. We can model each transaction as a tuple (x, y, z) which means person x gave person y $z. Assuming Alice, Bill, and Chris are person 0, 1, and 2 respectively (0, 1, 2 are the person's ID), the transactions can be represented as [[0, 1, 10], [2, 0, 5]].
Given a list of transactions between a group of people, return the minimum number of transactions required to settle the debt.
Note:
  1. A transaction will be given as a tuple (x, y, z). Note that x ≠ y and z > 0.
  2. Person's IDs may not be linear, e.g. we could have the persons 0, 1, 2 or we could also have the persons 0, 2, 6.
Example 1:
Input:
[[0,1,10], [2,0,5]]

Output:
2

Explanation:
Person #0 gave person #1 $10.
Person #2 gave person #0 $5.

Two transactions are needed. One way to settle the debt is person #1 pays person #0 and #2 $5 each.
Example 2:
Input:
[[0,1,10], [1,0,1], [1,2,5], [2,0,5]]

Output:
1

Explanation:
Person #0 gave person #1 $10.
Person #1 gave person #0 $1.
Person #1 gave person #2 $5.
Person #2 gave person #0 $5.

Therefore, person #1 only need to give person #0 $4, and all debt is settled.
------------------------
ToDo*再研究⼀下
dfs 返回的是 [i, end]这⼀段所最⼩小交易易数
参考http://www.mathmeth.com/tom/files/settling-debts.pdf 题意求最少的交易易次数。


class Solution {
    public int minTransfers(int[][] transactions) {
        Map<Integer, Integer> map = new HashMap<>();
        
        for (int[] i : transactions) {
            map.put(i[0], map.getOrDefault(i[0], 0) + i[2]);
            map.put(i[1], map.getOrDefault(i[1], 0) - i[2]);
        }
        
        List<Integer> debts = new ArrayList<>(map.values());
        return dfs(debts, 0); // 为什么选0?
    }
    
    private int dfs(List<Integer> debts, int start) {
        while (start < debts.size() && debts.get(start) == 0) {
            start++; // 遇到0后继续往下
        }
        
        if (start == debts.size()) return 0;
        int rt = Integer.MAX_VALUE;
        
        for (int i = start + 1; i < debts.size(); i++) {
            if (debts.get(start) * debts.get(i) < 0) {
                debts.set(i, debts.get(i) + debts.get(start));
                rt = Math.min(rt, 1 + dfs(debts, start + 1));
                debts.set(i, debts.get(i) - debts.get(start));
            }
        }
        
        return rt;
    }
}

变种:发现帐号不平衡后,怎么去平均
找一个中间人(可以为任意的人),其他人都给他转钱或取钱。
follow-up:优化。2种方法
1. 最少交易次数(就是LC这题了)
2. 最少交易额度, 预处理之后,用中间人的算法

from above ref:
1. generality (arbitrary number of lenders),
2. simplicity and practical feasibility,
3. minimized total amount transferred,
4. minimized total number of transfers, and
5. mathematical complexity of obtaining a solution.
There are, however, many other issues that might be considered, such as
1. charging interest on loans,
2. handling exchange rates for multiple currencies, and
3. dealing with distrust among the lenders.

Sunday, September 30, 2018

630. Course Schedule III

630Course Schedule III
There are n different online courses numbered from 1 to n. Each course has some duration(course length) t and closed on dthday. A course should be taken continuously for t days and must be finished before or on the dth day. You will start at the 1st day.
Given n online courses represented by pairs (t,d), your task is to find the maximal number of courses that can be taken.
Example:
Input: [[100, 200], [200, 1300], [1000, 1250], [2000, 3200]]
Output: 3
Explanation: 
There're totally 4 courses, but you can take 3 courses at most:
First, take the 1st course, it costs 100 days so you will finish it on the 100th day, and ready to take the next course on the 101st day.
Second, take the 3rd course, it costs 1000 days so you will finish it on the 1100th day, and ready to take the next course on the 1101st day. 
Third, take the 2nd course, it costs 200 days so you will finish it on the 1300th day. 
The 4th course cannot be taken now, since you will finish it on the 3300th day, which exceeds the closed date.
Note:
  1. The integer 1 <= d, t, n <= 10,000.
  2. You can't take two courses simultaneously.
---------------------------------
ToDo
class Solution {
    public int scheduleCourse(int[][] courses) {
        Arrays.sort(courses, (a, b) -> a[1] - b[1]);
        
        PriorityQueue<Integer> que = new PriorityQueue<>((a, b) -> b - a);
        int now = 0;
        for (int i = 0; i < courses.length; i++) {
            que.add(courses[i][0]);
            now += courses[i][0];
            if (now > courses[i][1]) {
                int ou = que.poll();
                now -= ou;
            }
        }
        
        return que.size();
    }
}

Wednesday, December 18, 2013

Day 58, #42, #43, #55, Trapping Rain Water, Multiply Strings, Jump Game II

Trapping Rain Water
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
For example,
Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6.


The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!
-----------------------------------------------------------------------------------
O(n) solution. for each bar, find the max height bar on the left and right. then for this bar it can hold min(max_left, max_right) - height
class Solution {
public:
    int trap(int A[], int n) {
        vector<int> leftMax(n,0);
        vector<int> rightMax(n,0);
        
        // get left max for each element
        for (int i = 1; i < n; i++) {
            leftMax[i] = max(leftMax[i - 1],A[i - 1]);
        }
        
        // get right max for each element
        for (int i = n - 2; i >= 0; i--) {
            rightMax[i] = max(rightMax[i + 1], A[i + 1]);
        }
        
        int sum = 0;
        for (int i = 0; i < n; i++) {
            int water = min(leftMax[i],rightMax[i]) - A[i]; 
            if (water > 0) {
                sum += water; 
            }
        }
        return sum;
    }
};
Update on Nov-6th-2014
come back
Solution #2, if leftMax < rightMax, leftIndex can contain (leftMax - A[leftIndex]) water, regardless what it looks like between leftIndex and rightIndex
class Solution {
public:
    int trap(int A[], int n) {
        int sum = 0;
        int leftMax = 0, rightMax = 0;
        int leftIndex = 0, rightIndex = n - 1;
        
        while (leftIndex <= rightIndex) {
            leftMax = max(leftMax,A[leftIndex]);
            rightMax = max(rightMax,A[rightIndex]);
            if (leftMax < rightMax) {
                sum += leftMax - A[leftIndex];
                leftIndex++;
            }else {
                sum += rightMax - A[rightIndex];
                rightIndex--;
            }
        }
        
        return sum;
    }
};
Multiply Strings
Given two numbers represented as strings, return multiplication of the numbers as a string.
Note: The numbers can be arbitrarily large and are non-negative.
--------------------------------------
Multiply numbers using straightforward math
class Solution {
public:
    string multiply(string num1, string num2) {
        int len1 = num1.length(), len2 = num2.length();
        string sum(len1 + len2,'0');
      
        for (int i = len1 - 1; i >= 0; i--) {
            int carry = 0;
            for (int j = len2 - 1; j >= 0; j--) {
                int cur = (sum[i + j + 1] - '0') + carry + (num1[i] - '0') * (num2[j] - '0');
                sum[i + j + 1] = cur % 10 + '0';
                carry = cur / 10;
            }
            sum[i] += carry;   
        }
        
        int start = 0;
        while (sum[start] == '0') {
            start++;
        }
        if (start == sum.length()) return "0";
        return sum.substr(start);
    }
};
Jump Game II
Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Your goal is to reach the last index in the minimum number of jumps.
For example:
Given array A = [2,3,1,1,4]
The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.)
---------------------------------------------------------------------------
Greedy, the point of this question is to find the largest distance with minimum steps
Every time 'i' passes curMax, increment step


class Solution {
public:
    int jump(int A[], int n) {
        int curMax = 0, newMax = 0;
        int step = 0;
        for (int i = 0; i < n; i++) {
            if (i > curMax) {
                // set up new max from old steps
                curMax = newMax;
                step++;
            }
            newMax = max(newMax,i + A[i]); // this line should be placed after if condition, 'cause new step has been made
        }
        return step;
    }
};
Update on Nov-7th-2014
a slightly different version, handles the case where the goal cannot be reached
class Solution {
public:
    int jump(int A[], int n) {
        if (n == 1) return 0;
        int step = 1;
        int currentReach = A[0];
        int maxCanReach = A[0];
        
        for (int i = 1; i < n; i++) {
            if (i > currentReach) {
                // to handle cases where the end cannot be reached
                if (currentReach == maxCanReach) {
                    return -1;
                }
                step++;
                currentReach = maxCanReach;
            }
            maxCanReach = max(maxCanReach,i + A[i]);
        }
        
        return step;
    }
};

Friday, October 11, 2013

Day 48, #116, #120, #123, Populating Next Right Pointers in Each Node, Triangle, Best Time to Buy and Sell Stock II

Populating Next Right Pointers in Each Node
Given a binary tree
    struct TreeLinkNode {
      TreeLinkNode *left;
      TreeLinkNode *right;
      TreeLinkNode *next;
    }
Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.
Initially, all next pointers are set to NULL.
Note:
  • You may only use constant extra space.
  • You may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two children).
For example,
Given the following perfect binary tree,

         1
       /  \
      2    3
     / \  / \
    4  5  6  7
After calling your function, the tree should look like:

         1 -> NULL
       /  \
      2 -> 3 -> NULL
     / \  / \
    4->5->6->7 -> NUL
-----------------------------------------------------------------
 typical level order tree traversal, can be implemented with either DFS or BFS
using an array to store the current tailing nodes, one slot for each level
/**
 * Definition for binary tree with next pointer.
 * struct TreeLinkNode {
 *  int val;
 *  TreeLinkNode *left, *right, *next;
 *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
 * };
 */
class Solution {
public:
    void traverse (TreeLinkNode* root, int curlevel, vector<TreeLinkNode*>& v) {
        if (root == NULL) {
            return;
        } 
        if (v.size() < curlevel) {
            v.push_back(root);
        }else{
            v[curlevel-1]->next = root;
            v[curlevel-1] = root;
        }
        traverse(root->left,curlevel+1,v);
        traverse(root->right,curlevel+1,v);
    }
    
    void connect(TreeLinkNode *root) {
        // Note: The Solution object is instantiated only once and is reused by each test case.
        vector<TreeLinkNode*> v;
        traverse(root,1,v);
    }
};

constant space
/**
 * Definition for binary tree with next pointer.
 * struct TreeLinkNode {
 *  int val;
 *  TreeLinkNode *left, *right, *next;
 *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
 * };
 */
class Solution {
public:
    void connect(TreeLinkNode *root) {
        while (root != NULL) {
            TreeLinkNode *pre = root;
            TreeLinkNode *before = NULL;
            while (pre != NULL && pre->left != NULL) {
                if (before != NULL) {
                    before->next = pre->left;
                }
                pre->left->next = pre->right;
                before = pre->right;
                pre = pre->next;
            }
            root = root->left;
        }
    }
};

Triangle

Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.
For example, given the following triangle

[
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]
The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).
Note:
Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle.
--------------------------------------------
DP in place
replace each element in level #i with the possible minimum sum that are added from level #i+1
class Solution {
public:
    int minimumTotal(vector<vector<int> > &triangle) {
        // Note: The Solution object is instantiated only once and is reused by each test case.
        int size = triangle.size();
        for (int row = size - 2; row >= 0; row--) {
            for (int index = 0; index < triangle[row].size(); index++) {
                triangle[row][index] += min(triangle[row+1][index],triangle[row+1][index+1]);
            }
        }
        return triangle[0][0];
    }
};
Best Time to Buy and Sell Stock II
Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
-----------------------------------------------------------------------
greedy
class Solution {
public:
    int maxProfit(vector<int> &prices) {
        // Note: The Solution object is instantiated only once and is reused by each test case.
        int sum = 0;
        for (int i = 1; i < prices.size(); i++) {
            int dif = prices[i] - prices[i - 1];
            if (dif > 0) {
                sum += dif;
            }
        }
        return sum;
    }
};