Friday, July 3, 2015

Day 115, #229, Majority Element II, Kth Smallest Element in a BST

Majority Element II
Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times. The algorithm should run in linear time and in O(1) space.
Hint:
  1. How many majority elements could it possibly have?
---------------------------------------
注意for loop里的判断
class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        vector<int> rt;
        if (nums.size() == 0) return rt;
        
        int num1 = 0, num2 = 0, count1 = 0, count2 = 0;
        for (int i = 0; i < nums.size(); i++) {
            if (count1 == 0 && (count2 == 0 || nums[i] != num2)) {
                num1 = nums[i];
                count1++;
            }else if (count2 == 0 && nums[i] != num1){
             count2++;
             num2 = nums[i];
            }else if (nums[i] == num1) {
                count1++;
            }else if (nums[i] == num2) {
                count2++;
            }else {
                count1--;
                count2--;
            }
        }
        
        count1 = 0;
        count2 = 0;
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] == num1) count1++;
            else if (nums[i] == num2) count2++;
        }
        if (count1 * 3 > nums.size()) rt.push_back(num1);
        if (count2 * 3 > nums.size()) rt.push_back(num2);
        return rt;
    }
};

Kth Smallest Element in a BST
Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.
Note: 
You may assume k is always valid, 1 ≤ k ≤ BST's total elements.
Follow up:
What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine?
-------------------------------------------------------------------------------
COME BACK for the follow up
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void preorder(TreeNode* root, int &k, TreeNode *&kth) {
        if (root == NULL) return;
        preorder(root->left,k,kth);
        k--;
        if (k == 0) kth = root;
        else preorder(root->right,k,kth);
    }

    int kthSmallest(TreeNode* root, int k) {
        TreeNode *kth = NULL;
        preorder(root,k,kth);
        return kth->val;
    }
};

另一种做法,找出子树的数量 updated on Jan-4th-2019
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private TreeNode rt = null;
    public int kthSmallest(TreeNode root, int k) {
        dfs(root, k);
        return rt.val;
    }
    
    private int dfs(TreeNode root, int k) {
        if (root == null) return 0;
        int l = dfs(root.left, k);
        
        if (l + 1 == k) {
            rt = root;
        }
        
        int r = dfs(root.right, k - l - 1);
        return l + r + 1;
    }
}

Follow up
修改TreeNode结构,加入count。O(n)重建树,O(lg n) 找到Kth smallest

Google interview questions #2

REF http://www.mitbbs.com/article_t/JobHunting/32996813.html
phone: 1.given an order string "abc" check if "aabdccd" maintain the order
       "aabdccd" -> true;
       "abbca"   -> false;
note:order does not contain all chars in s
bool checkOrder(string order, string s) {
 vector<int> v(256,-1);
 
 for (int i = 0; i < order.size(); i++) {
  v[order[i]] = i;
 }
 
 int curOrder = 0;
 for (int i = 0; i < s.length(); i++) {
  if (v[s[i]] == -1) continue;
  if (v[s[i]] < curOrder) {
   return false;
  }
  curOrder = v[s[i]];
 }
 
 return true;
}


       2.abbre word, given a list of words, return a map contains abbre word
map to a list of original word
       abbre word means:   word -> w2d,  international -> i11l
       跟anagram差不多
COME_BACK
onsite: 1.毛子 given "AABBCC" return "ABCABC", no same char next to each 
other
          "ABBB" -> exception
          "ABBA" -> "ABAB"

用map记录下所有字符出现的次数,若某一个字符超过(总数 + 1)/ 2以上则为exception
在while loop之后,最终没有字符或者只会有一种字符被拉下,然后从头开始填充
*思考constant space的解法

string noNext(string s) {
    unordered_map map;
     for (int i = 0; i < s.length(); i++) {
        if (map.find(s[i]) == map.end()) {
            map[s[i]] = 1;
        }else {
        map[s[i]]++;
        }
     }
    string temp;
    temp.resize(s.length());
  
    char left = '\0';
    int i = 0;
    bool flag = true;
    while (i < temp.length() && flag) {
        for (auto kv : map) {
            if (map[kv.first] > (temp.length() + 1) / 2) return "exception";
            if (map[kv.first] != 0) {
                if (i != 0 && kv.first == temp[i - 1]) {
                    left = kv.first;
                    flag = false;
                    break;
                }
                temp[i] = kv.first;
                map[kv.first]--;
                i++;
            }
        
        }
    }
    if (i == temp.length()) return temp;
  
    string rt;
    int index = 0;
    rt.resize(temp.length());
      
    if (temp[0] != left) {
        rt[index] = left;
        index++;
        map[left]--;
    }
  
    for (int j = 0; j < temp.length() && index < temp.length(); j++) {
        rt[index] = temp[j];
        index++;
        if (map[left] > 0 && left != temp[j] && left != temp[j + 1]) {
            rt[index] = left;
            index++;
            map[left]--;
        }
    }
 
    return rt;
}



        2.国人 excel encoding, leetcode那个
          given [1,2,0,6,9] and target 81, return true if add “+” between 
numbers can add up to target. 12+0+69=81 -> true.
类似subset题目,将每个数字之间的加号为设为“有”或“无”
注意base case 为 target == curSum, 不是target = 0

bool helper(vector<int> &nums, int target, int curSum, int index) {
    if (index == nums.size() && target == curSum) return true;
    if (target < 0 || index >= nums.size()) return false;
  
    if (helper(nums,target, curSum * 10 + nums[index],index + 1)) {
        return true;
    }
    if (index != 0 && helper(nums,target - curSum,nums[index],index + 1)) {
        return true;
    }
      
    return false;
}
 
bool possibleSum(vector<int> &nums, int target) {
    return helper(nums,target,0,0);
}

        3.白人小哥 java 一个数据结构改错,没什么tricky的地方
        4.三哥 abbre word again... follow up是 word->w2d, 另一个wold->wo1d, 
也就是说不能group起来,每个都是unique的
返回所有可能的abbreviation

vector<string> allAbbre(string s) {
    vector<string> rt;
    if (s.length() == 0) return rt;
    if (s.length() < 3) {
        rt.push_back(s);
        return rt;
    }
    
    for (int i = 0; i < s.length() - 1; i++) {
        string prefix = s.substr(0,i + 1);
        for (int j = s.length() - 1; j > i + 1; j--) {
            string suffix = s.substr(j);
            rt.push_back(prefix + to_string(j - i - 1) + suffix);
        }
    }
    
    return rt;
}


        5.毛子 maximum path from upper left to right bottom, follow up是除了
往下往右,还可以往左走,怎么避免死循环。
follow up用BFS / dijkstra 
-------------------------------------------------
REF http://www.mitbbs.com/article_t/JobHunting/33000225.html
给一个起点,一个终点,然后已知这个人从起点到终点的所有线段,但是打乱了,要你
复原走的路线。
难点是路线里面可能有Cycle,而且会重复。

比如给的是A-->F
线段是 B->C, D->E, A->B, C-D, E->B, B->C, C->F

复原结果是 A B C D E B C F

------------------------------------
需要建立有向图 #1 recursion + back track
设一个set来存所有的edge,走过的就删掉
base case 是当edge为空,此时又刚好到达终点
另一个是当edge为空,此时到达不了终点,或者当前点无路可走。然后返回上一步,换
一条路径

#2 permutation,permute所有线段,然后走一遍检测。优化条件是每段线的头尾是否
是相连
----------------------------------------------

Thursday, July 2, 2015

Day 114, Lintcode, #395, Coins in a Line II

Coins in a Line II
There are n coins with different value in a line. Two players take turns to take one or two coins from left side until there are no more coins left. The player who take the coins with the most value wins.
Could you please decide the first player will win or lose?
-----------------------------------------------------
方法一
coins表示在i点的最大利益
getTwo表示在i点最大利益是否要取2个coin
class Solution {
public:
    /**
     * @param values: a vector of integers
     * @return: a boolean which equals to true if the first player will win
     */
    bool firstWillWin(vector<int> &values) {
        // write your code here
        int m = values.size();
        if (m < 3) return true;
        
        vector<int> coins(m + 2,0);
        vector<bool> getTwo(m,true);
        
        coins[m - 1] = values[m - 1];
        coins[m - 2] = values[m - 1] + values[m - 2];
        
        for (int i = m - 3; i >= 0; i--) {
            int takeOne = 0, takeTwo = 0;
            // take one
            if (getTwo[i + 1]) {
                takeOne = coins[i + 3] + values[i];
            }else {
                takeOne = coins[i + 2] + values[i];
            }
            
            // take two
            if(getTwo[i + 2]) {
                takeTwo = coins[i + 4] + values[i] + values[i + 1];
            }else {
                takeTwo = coins[i + 3] + values[i] + values[i + 1];
            }
            
            coins[i] = max(takeOne,takeTwo);
            if (takeOne > takeTwo) {
                getTwo[i] = false;
            }
        }
        
        if (getTwo[0]) {
            return coins[0] > coins[2];
        }
        return coins[0] > coins[1];
    }
};

方法二 http://techinpad.blogspot.com/2015/05/lintcode-coins-in-line-ii.html
方法三 http://www.meetqun.com/thread-9798-1-1.html

Friday, June 26, 2015

总结

general
遇到问题将算法模块化,可以假设一些方法已经给出或者之后再编写,可以加快找出主体思路的速度,减少浪费时间在细节上

*先想test case

-----------------------------------------------------------------------
tree

https://www.topcoder.com/community/data-science/data-science-tutorials/an-introduction-to-binary-search-and-red-black-trees/



#遇到prefix,stream of strings等,上tries

#(写法)递归时,在返回所需要的极值,传入pointer同时计算partial的值(如height,path sum)
例子:
LC #124 Binary Tree Maximum Path Sum
GeeksforGeeks: Diameter of a Binary Tree
# 另一种写法,返回的是partial的值,参数中pass by reference一个极值

#(写法) bfs,用一个queue和size来区分每一层,例子:level order traversal等等 #1 bst
遇到bst题目先考class Solution {
public:
    int minCost(vector&lt;vector&lt;int&gt;&gt;&amp; costs) {
        int n = costs.size();
        if (n == 0) return 0;
        int dp0 = costs[0][0];
        int dp1 = costs[0][1];
        int dp2 = costs[0][2];
        
        for (int i = 1; i &lt; n; i++) {
            int t0 = dp0, t1 = dp1, t2 = dp2;
            dp0 = costs[i][0] + min(t1,t2);
            dp1 = costs[i][1] + min(t2,t0);
            dp2 = costs[i][2] + min(t1,t0);
        }

        return min(min(dp0,dp1),dp2);
    }
};虑in place遍历方法:pre - in - post(#94,#144,#145,#105,#106)
注:#94跟#173的单stack写法

dfs寻找路径,可以用一个大小为树的高度的vector跟int level表示当前高度

-----------------------------------------------------------------------
string
palindrome(LC: #5, #9, #125, #131, #132, #214), 可以预先用DP检测palindrome存值

-----------------------------------------------------------------------
dp
from Tara: 局部最优解关键词:最大,最小,至少,至多

从recursion引出dp

string类的,先从小的test case下手,如(ab,b) 
例题:LC #115,distinct subsequence

矩阵类(见矩阵词条)

多层dp,paint house

-----------------------------------------------------------------------
array
直接上:双指针和hashmap
-----------------------------------------------------------------------
subsets / combination
此类问题有2种解题思路(LC #90,#77,#39, #40)
假如有集合{1,2,3,4,5}
#1 传统combination
递归: 第一层递归,每次取{}空集合,各插入一元素。第二层递归,此时集合内含有一个元素,每次插入index大于它的元素
第一层{1},{2}, {3}, {4}, {5}
第二层{1, 2}, {1,3},{1,4}, {1,5},{2, 3}, {2,4},{2,5},{3,4}.....
第三层{1,2,3},{1,2,4},{1,2,5},{1,3,4},{1,3,5}.....{2,3,4},{2,3,5}......
.....

遍历:看LC #90 Subsets代码

#2 类似bitmap
集合内的每个元素都有2种情况--被包括在集合或不被包括在集合
递归:见Google interview questions #2,第2题

遍历:
subsets的总个数为 2^原集合的大小,设一个loop大小为总个数,把每一个从0 到 总个数 - 1(看做二进制)的数作为bit mask,来跟原集合对应
看LC #90 Subsets代码
-----------------------------------------------------------------------
math
#1加减法, LC #2,#66,#67, 
#1 各种类型与integer的暂时互相转化
#2 carry可以用来当sum用
#3 loop的终止条件配合loop内的判断
#4 dummy node


--------------------------------------------------------------------
矩阵
矩阵路径:如果只能往下和往右走的话,用recursion或者dp (LC #130, #200)
如果增加其他方向,Dijkstra和普通的BFS都可以适用 (Google interview questions #3, 后几题) (Google interview questions #2, 第5题follow up)


矩阵中找最大的sub矩阵:
LC:#85 Maximal Rectangle, #221 Maximal Square, Google interview #6 倒数第2道http://www.geeksforgeeks.org/dynamic-programming-set-27-max-sum-rectangle-in-a-2d-matrix/

------------------------------------------------------------------------
Linked List
快慢指针的使用:
如下循环结束后,slow将指向中点(奇数个)或指向后半部分的起点(偶数个)
ListNode *slow = head, *fast = head;
while (fast != NULL) {
    fast = fast->next;
    if (fast != NULL) {
        fast = fast->next;
        slow = slow->next;
    }
}

-------------------------------------------------------------------------
点跟线段,坐标
sort x或y
closest pair of points(code 见coursera 第一章)

找median
example: 见google interview #5 第1,2部分 的oil pipe,朋友矩阵

------------------------------------------------------------------
随机性的题(待写)
general,高中概率论:某个值最终被选中的概率 = 当前被选中的概率 * 之前没被选中的概率

扑克牌http://www.geeksforgeeks.org/shuffle-a-given-array/

用ran(5)生成ran(7): 二维数组
{[1,2,3,4,5],
  [6,7,1,2,3],
  [4,5,6,7,1],
  [2,3,4,5,6],
  [7,0,0,0,0]}

Reservoir sampling: Google interview questions #4 倒数第2题
https://en.wikipedia.org/wiki/Reservoir_sampling
http://www.geeksforgeeks.org/reservoir-sampling/

-------------------------------------------------------------
Sorting
Merge sort: count inversions, LC # 148,#88,#23,#21
radix sort/count sort/bucket sort: LC #164

------------------------------------------------------------------
游戏算法
https://www.topcoder.com/community/data-science/data-science-tutorials/%20algorithm-games/
定理:
  • All terminal positions are losing.
  • If a player is able to move to a losing position then he is in a winning position.
  • If a player is able to move only to the winning positions then he is in a losing position.

第一个例子:The Game of Nim
当所有piles的size xor之后如果是0的话,当前为losing position,因为输的条件是0,从0开始第一步肯定会让xor的值变成非0。
如果当前xor为非0,则从最左侧的1的个数为奇开始,改变当前的pile,可使xor变成0

------------------------------------------------------------
Binary search
(写法)
while (left <= right) {
    ....
}
if target is not found, after the search, "left" is always the index where target should be inserted. and "right" equals to "left - 1"
LC #35, #74, #240

----------------------------------------
Divide and conquer
切两半,需要的值可能在任意一边,或者是横跨两边。
example:closest pair of points, lc #53 maximum subarray,

-------------------------------------------------------
Recursion
(写法)对于求各种集合的题(如permutation,combination,求所有path),sub-set可以用pass by reference来代替,减少递归时的空间,LC #113 Path Sum II

---------------------------------------------------
Graph
bfs: 例题:person找血缘关系,第2部分第8题

Union find: 代码,google interview #7 第一部分第1题
http://blog.csdn.net/dm_vincent/article/details/7655764
The input is a sequence of pairs of integers, where each integer represents an object of some type and we are to interpret the pair p q as meaning p is connected to q. We assume that "is connected to" is an equivalence relation:
case study:
http://algs4.cs.princeton.edu/15uf/

-----------------------------------
Interval的题
排序,merge或者split,见google#6,飞哥的题。LC的那几道

------------------------------------------
sliding window的题
当发现至少一个window符合要求时,以后的操作都要维护、保持这个window的合法性
例子: LC #3 Longest Substring Without Repeating Characters, #76 Minimum Window Substring 等等

--------------------------------------------------
Longest sub-string/sequence 类
考虑DP,lintcode上有一套



Google interview questions #1

找出二叉查找树中出现频率最高的元素。树中结点满足left->val <= root->val <= right->val。如果多个元素出现次数相等,返回最小的元素。 http://blog.csdn.net/luckyxiaoqiang/article/details/8934593

不用额外空间. in-order

struct TreeNode{
   int val;
   TreeNode *left;
   TreeNode *right;
   TreeNode(int val) {
      this->val = val;
   }
};

void countNodesHelper(TreeNode *root, TreeNode *&pre, int &count, int &maxCount) {
 if (root == NULL) return;
 countNodesHelper(root->left,pre,count,maxCount);
 
 if (pre == NULL) {
    pre = root;
    count = 1;
  
 }else {
    if (pre->val == root->val) {
       count++;
       if (maxCount < count) {
          maxCount = count;
       }
    }else {
       count = 1;
    }
 }
   pre = root;
   countNodesHelper(root->right,pre,count,maxCount);
}

int countNodes(TreeNode *root) {
   int maxCount = 0,count = 0;
   TreeNode *pre = NULL;
   foo(root,pre,count,maxCount);
   return maxCount;
}
-----------------------------------------------
有一个函数
long compute(int i) {
return …;
}
返回值有可能出错概率是 p=1/10000。

还有一个函数
long total(int n) {
long s = 0;
for (int i =0; i < n; i++) {
   s += compute(i);
}
return s;
}
这样出错概率就是 np;

问: 如何改第二个函数,让他的出错概率小于p?

http://www.mitbbs.com/article_t/JobHunting/32996657.html
----------------------------------------------------------------------------------------------
REF http://www.mitbbs.com/article_t/JobHunting/32980969.html

1:(1):写一个bool Palindrome(string s),就是测s是否是Palindrome。
      (2):已知bool Palindrome(string s)方程,写一个 int howmanyPalindrome
(string s), 输入s,返回s中包含多少个Palindrome的单词。 例如abbbac返回10,有a
,b,b,b,a,c,bb, bbb, bb, abbba.


int countHelper(string &s, int left, int right) {
   int count = 0;
 
   while (left >= 0 && right < s.length()) {
      if (s[left] == s[right]) {
         count++;
         right++;
         left--;
      }else {
         break;
      }
   }
   
   return count;
}
 
int countPal(string s) {
   int count = 0;
  
   for (int i = 1; i < s.length(); i++) {
      count += countHelper(s,i - 1,i); // even
      count += countHelper(s,i,i); // odd
   }
  
   return count + 1;
}


2: 给一个树root的pointer,树包含多个分支,树结构要自己创造。求一条最长[连续]
路径。
例如(括号对应上面node)  [修改:还有条件是 连续]
   树:                     2
                 |            |            |                |
                5            7          3                 6
         (|       | )(   | )   (|)         (|       |)
            6       3         2          4             5       8
                                 |
                                  3

返回3因为 (2-3-4) 这条线。优化要求时间O(n)
DFS,tree寻找路径
increasing order
struct TreeNode {
    int val;
    vector children;
    TreeNode(int val) {
        this->val = val;
    }
};
 
int longestPathHelper(TreeNode *root, int &longest) {
  
    int cur = 1;
    for (int i = 0; i < root->children.size(); i++) {
        TreeNode *child = (root->children)[i];
        if (root->val == child->val - 1) {
            cur = max(cur,longestPathHelper(root->children[i],longest) + 1);
        }else {
            cur = longestPathHelper(child,longest);
        }
   
    }
    longest = max(cur,longest);
    return cur;
}
 
int longestIncreasingPath(TreeNode *root) {
    if (root == NULL) return 0;
    int longest = 0;
    longestPathHelper(root,longest);
    return longest;
}

返回路径
struct TreeNode {
    int val;
    vector<TreeNode *> children;
    TreeNode(int val) {
        this->val = val;
    }
};
 
void longestPathHelper(TreeNode *root,TreeNode *pre, vector<int> path, vector<int> &longestPath) {
    vector<int> curLongest;
    if (pre != NULL && root->val == pre->val + 1) {
        curLongest = path;    
    }
    curLongest.push_back(root->val);

    for (int i = 0; i < root->children.size(); i++) {
        longestPathHelper(root->children[i],root,curLongest,longestPath);
    }
    
    if (longestPath.size() < curLongest.size()) {
        longestPath = curLongest;    
    } 
}
 
void longestIncreasingPath(TreeNode *root) {
    vector<int> longestPath,path;
    if (root == NULL) return;
    
    longestPathHelper(root,NULL,path,longestPath);
    for (int i : longestPath) {
        cout << i << endl;
    }
}

3.时间区间合并问题,leetcode上有相似题,关键词interval

4.(1)一个sorted array,如果其中有一个数重复超过array里面总数的1/4 return 
true。就是说{2,2,3,4} return true
{1,1,2,3,4,5,6,7} return false。
(2)优化第一部分用O(log2(N)) 时间复杂度
如果存在超过 1/4 的数,则次数必定会覆盖length / 4, length / 2, length *(3 / 4)这3点中的至少一点,所以只要对这3点上的数做二分搜索,就能找到其长度,然后与 1 / 4的长度对比。复杂度为 O(lgN)
int findFirst(vector<int> &nums, int elem) {
  int left = 0, right = nums.size() - 1;
  
  while (left <= right) {
    int mid = left + (right - left) / 2;
    if (nums[mid] == elem) {
      if (mid - 1 >= 0 && nums[mid - 1] != nums[mid]) {
         return mid;
      }
      right = mid - 1;
    }else if (nums[mid] > elem) {
      right = mid - 1;
    }else {
      left = mid + 1;
    }
  }
  
  return 0;
}

int findLast(vector<int> &nums, int elem) {
  int left = 0, right = nums.size() - 1;
  
  while (left <= right) {
    int mid = left + (right - left) / 2;
    if (nums[mid] == elem) {
      if (mid + 1 < nums.size() && nums[mid + 1] != nums[mid]) {
       return mid;
      }
      left = mid + 1;
    }else if (nums[mid] > elem) {
      right = mid - 1;
    }else {
      left = mid + 1;
    }
  }
  
  return 0;
}

bool helper(vector<int> &nums, int index) {
  int last = findLast(nums,nums[index]);
  int first = findFirst(nums,nums[index]);
  
  if (last - first + 1 > nums.size() / 4) {
    return true;
  }
  
  return false;
}

bool longerThanAQuarter(vector<int> &nums) {
  int length = nums.size();
  return helper(nums,length / 4) || helper(nums,length / 2) || helper(nums,length - 1 -length / 4);
}

(3)完全平方解集,做一个:int minsol(int i)。
比如1=1^2 所以minsol(1)返回1,
2=1^2+1^2 返回2,
4=2^2或者4个1^2,1比4小, 返回1,
12=2^2+2^2+2^2或者3^2+3个1^2返回3.

DP
int shortest(int num) {
    int t = sqrt(num);
    if (t * t == num) return 1;
       
    vector<int> dp(num + 1,INT_MAX);
    dp[1] = 1;
    dp[2] = 2;
    
    for (int i = 3; i <= num; i++) {
    int sq = sqrt(i);
        if (sq * sq == i) {
            dp[i] = 1;
        }else {
            for (int j = 1; j < i / 2 + 1; j++) {
                dp[i] = min(dp[i],dp[j] + dp[i - j]);
            }
        }
    }
    
    return dp.back();
}


5.有一个游戏,他说是fishing game,给一个数组vector<int> Basket, 比如里面元素
是{2,3,5,1,3,4,7}
有A,B 2个player,规定只能从Basket2端选数字,意思就是A开始的话一开始A只能选2
或者7,然后B选,同样只能2端选。所以比如一开始A选了7,B只能从2和4中选。问给定
数组A能取的最大值。B的策略已知,是greedy,就是总会取最大的那个数。
写一个 int maxA(vector<int>& Basket);
Lintcode, Coins in a Line III http://www.lintcode.com/en/problem/coins-in-a-line-iii/#
DP, Memoization. iteration待写

int helper(vector<int> &nums, int start, int end, vector<vector<int> > &dp) {
    if (start == end) return 0;
    if (start + 1 == end) {
        return min(nums[start],nums[end]);
    }
 
    if (dp[start][end] != 0) return dp[start][end];

    if (nums[start] < nums[end]) {
        end--;
    }else {
        start++;
    }
 
    int play_1 = helper(nums,start + 1,end,dp) + nums[start];
    int play_2 = helper(nums,start,end - 1,dp)  + nums[end];
 
    dp[start][end] = max(play_1,play_2);
    return max(play_1,play_2);
}

int play(vector<int> &nums) {
    vector<vector<int> > dp(nums.size(),vector<int>(nums.size(),0));

    return max(helper(nums,0,nums.size() - 2, dp) + nums[nums.size() - 1],helper(nums,0,nums.size() - 2, dp) + nums[nums.size() - 1]);
}


Thursday, June 25, 2015

Day 113, ##, Basic Calculator II, Summary Ranges

Basic Calculator II
Implement a basic calculator to evaluate a simple expression string.
The expression string contains only non-negative integers, +-*/ operators and empty spaces . The integer division should truncate toward zero.
You may assume that the given expression is always valid.
Some examples:
"3+2*2" = 7
" 3/2 " = 1
" 3+5 / 2 " = 5
Note: Do not use the eval built-in library function.
--------------------------------------------------
look ahead,COME_BACK, 如果加入括号呢?
注意对i的处理
class Solution {
public:
    long long lookAhead(string &s, int &i) {
        long long num = 0;
        while (i < s.length()) {
            if (s[i] == ' ') {
                i++;
            }else if (isdigit(s[i])) {
                num = 10 * num + s[i] - '0'; 
                i++;
            }else
                break;
        }
        
        i--;
        return num;
    }

    int calculate(string s) {
        long long num = 0, rt = 0;
        long long sign = 1;
        
        for (int i = 0; i < s.length(); i++) {
            if (isdigit(s[i])) {
                num = lookAhead(s,i);
            }else if (s[i] == '+') {
                rt += sign * num;
                sign = 1;
                num = 0;
            }else if (s[i] == '-') {
                rt += sign * num;
                sign = -1;
                num = 0;
            }else if (s[i] == '*') {
                i++;
                num *= lookAhead(s,i);
            }else if (s[i] == '/') {
                i++;
                num /= lookAhead(s,i);
            }
        }
        
        if (num > 0) return rt + sign * num;
        return rt;
    }
};

Summary Ranges 
Given a sorted integer array without duplicates, return the summary of its ranges.
For example, given [0,1,2,4,5,7], return ["0->2","4->5","7"].
----------------------------------------------------------
nums[i] == nums[i - 1] + 1 与 nums[i] - nums[i - 1] == 1 相比较,前者不会有溢出的问题
re-factory之后的代码
class Solution {
public:
    vector<string> summaryRanges(vector<int>& nums) {
        int start = 0;
        vector<string> rt;
        if (nums.size() == 0) return rt;
        
        for (int i = 1; i <= nums.size(); i++) {
            if (i == nums.size() || nums[i] != nums[i - 1] + 1) {
                if (i - start == 1) {
                    rt.push_back(to_string(nums[start]));
                }else {
                    rt.push_back(to_string(nums[start]) + "->" + to_string(nums[i - 1]));
                }
                start = i;
            }
        }
        
        return rt;
    }
};
re-factory之前的代码
class Solution {
public:
    vector<string> summaryRanges(vector<int>& nums) {
        int start = 0;
        vector<string> rt;
        if (nums.size() == 0) return rt;
        
        for (int i = 1; i < nums.size(); i++) {
            if ((long long)nums[i] - (long long)nums[i - 1] == 1) {
                continue;
            }
            if (i - start == 1) {
                string s = to_string(nums[start]);
                rt.push_back(s);
                start = i;
            }else {
                string s = to_string(nums[start]) + "->" + to_string(nums[i - 1]);
                rt.push_back(s);
                start = i;
            }
        }
        
        if (start == nums.size() - 1) {
            string s = to_string(nums[start]);
            rt.push_back(s);
        }else {
            string s = to_string(nums[start]) + "->" + to_string(nums.back());
            rt.push_back(s);
        }
        
        return rt;
    }
};

Wednesday, June 24, 2015

Day 112, ##, Count Complete Tree Nodes, Rectangle Area, Basic Calculator, Implement Stack using Queues, Invert Binary Tree

Count Complete Tree Nodes
Given a complete binary tree, count the number of nodes.
Definition of a complete binary tree from Wikipedia:
In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. It can have between 1 and 2hnodes inclusive at the last level h.
--------------------------------------------
O(logN * logN),遇到perfect tree, 直接计算并返回,反之继续数儿子们
看了答案
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int countNodes(TreeNode* root) {
       if (root == NULL) return 0;
       int left = 0, right = 0;
       TreeNode *leftItr = root, *rightItr = root;
       while (leftItr != NULL) {
           left++;
           leftItr = leftItr->left;
       }
       
       while (rightItr != NULL) {
           right++;
           rightItr = rightItr->right;
       }
       
       if (left == right) return pow(2,left) - 1;
       return 1 + countNodes(root->left) + countNodes(root->right);
    }
};

iterative
检查右子树是不是perfect tree,如果是,则缺口在左子树,此时加上右边的个数。
如果不是,则缺口在右子树,此时加上左边的个数
此题关键在于对高度的判断,然后对树的分解
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int getHeight(TreeNode *root) {
        int height = 0;
        while (root != NULL) {
            height++;
            root = root->left;
        }
        
        return height;
    }

    int countNodes(TreeNode* root) {
        int height = getHeight(root);
        int count = 0;
        while (root != NULL) {
            if (getHeight(root->right) == height - 1) {
                count += 1 << height - 1;
                root = root->right;
            }else {
                count += 1 << height - 2;
                root = root->left;
            }
            
            height--;
        }
        
        return count;
    }
};

Rectangle Area
Find the total area covered by two rectilinear rectangles in a 2D plane.
Each rectangle is defined by its bottom left corner and top right corner as shown in the figure.
Rectangle Area
Assume that the total area is never beyond the maximum possible value of int.
----------------------------------------------
看了答案
class Solution {
public:
    int computeArea(int A, int B, int C, int D, int E, int F, int G, int H) {
        if (D < F || H < B || G < A || C < E) {
            return (H - F) * (G - E) + (C - A) * (D - B);
        }
        
        int right = min(D,H) - max(B,F);
        int top = min(C,G) - max(E,A);
        
        return (D - B) * (C - A) + (H - F) * (G - E) - right * top;
    }
};

Basic Calculator
Implement a basic calculator to evaluate a simple expression string.
The expression string may contain open ( and closing parentheses ), the plus + or minus sign -non-negative integers and empty spaces .
You may assume that the given expression is always valid.
Some examples:
"1 + 1" = 2
" 2-1 + 2 " = 3
"(1+(4+5+2)-3)+(6+8)" = 23
---------------------------------------------------------------------
看了答案,用初始化 sign = 1来处理符号,能解决特殊情况.
对()的处理
class Solution {
public:
    int calculate(string s) {
        stack<int> st;
        int sign = 1;
        int rt = 0;
        int num = 0;
        
        for (int i = 0; i < s.length(); i++) {
            if (isdigit(s[i])) {
                num = num * 10 + s[i] - '0';
            }else if (s[i] == '+') {
                rt += sign * num;
                sign = 1;
                num = 0;
            }else if (s[i] == '-') {
                rt += sign * num;
                sign = -1;
                num = 0;
            }else if (s[i] == '(') {
                st.push(rt);
                st.push(sign);
                sign = 1;
                rt = 0;
            }else if (s[i] == ')') {
                rt += num * sign;
                sign = st.top();
                st.pop();
                rt = sign * rt + st.top();
                st.pop();
                num = 0;
            }
        }
        
        if (num != 0) {
            return rt + sign * num;
        }
        
        return rt;
    }
};
Java, updated on Aug-16th-2018. 整体思路类似,只不过遇到数字做加减。上面c++的算法是遇到符号做加减。
class Solution {
    public int calculate(String s) {
        Stack<Integer> st = new Stack<>();
        int i = 0;
        int eval = 0;
        int sign = 1;
        
        while (i < s.length()) {
            char c = s.charAt(i);
            if (c == '(') {
                st.push(eval);
                st.push(sign);
                eval = 0;
                sign = 1;
            }else if (c == ')') {
                sign = st.pop();
                eval = st.pop() + eval * sign;
            }else if (Character.isDigit(c)) {
                String cur = "";
                while (i < s.length() && Character.isDigit(s.charAt(i))) {
                    cur += s.charAt(i);
                    i++;
                }
                i--;
                eval += sign * Integer.parseInt(cur);
            }else if (c == '-') {
                sign = -1;
            }else if (c == '+') {
                sign = 1;
            }
            
            i++;
        }
        
        return eval;
    }
}

Implement Stack using Queues
Implement the following operations of a stack using queues.
  • push(x) -- Push element x onto stack.
  • pop() -- Removes the element on top of the stack.
  • top() -- Get the top element.
  • empty() -- Return whether the stack is empty.
Notes:
  • You must use only standard operations of a queue -- which means only push to backpeek/pop from frontsize, and is empty operations are valid.
  • Depending on your language, queue may not be supported natively. You may simulate a queue by using a list or deque (double-ended queue), as long as you use only standard operations of a queue.
  • You may assume that all operations are valid (for example, no pop or top operations will be called on an empty stack).
----------------------------------------------------
用queue的大小来控制倒腾,只用一个queue,而不是两个
class Stack {
public:
    // Push element x onto stack.
    void push(int x) {
        topElem = x;
        q.push(x);
    }

    // Removes the element on top of the stack.
    void pop() {
        for (int i = 0; i < q.size() - 1; i++) {
            topElem = q.front();
            q.push(q.front());
            q.pop();
        }
        q.pop();
    }
    
    // Get the top element.
    int top() {
        return topElem;
    }

    // Return whether the stack is empty.
    bool empty() {
        return q.empty();
    }
private:
    queue<int> q;
    int topElem;
};

Invert Binary Tree
Invert a binary tree.
     4
   /   \
  2     7
 / \   / \
1   3 6   9
to
     4
   /   \
  7     2
 / \   / \
9   6 3   1
---------------------------------------------------
recursive
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if (root == NULL) return NULL;
        TreeNode *temp = root->left;
        root->left = invertTree(root->right);
        root->right = invertTree(temp);
        
        return root;
    }
};

iterative
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if (root == NULL) return root;
        queue<TreeNode *> que;
        que.push(root);
        
        while (!que.empty()) {
            TreeNode *node = que.front();
            que.pop();
            TreeNode *temp = node->left;
            node->left = node->right;
            node->right = temp;
            
            if (node->left != NULL) {
                que.push(node->left);
            }
            if (node->right != NULL) {
                que.push(node->right);
            }
        }
        
        return root;
    }
};