IT技術小屋

          秋風秋雨,皆入我心

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            38 隨筆 :: 1 文章 :: 19 評論 :: 0 Trackbacks

          #

          Distinct Subsequences

          Given a string S and a string T, count the number of distinct sub sequences of T in S.
          A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not).
          Here is an example:
          S = "rabbbit", T = "rabbit"
          Return 3.

          這兩個題目很相似,狀態方程是f(i, j) = f(i - 1, j) + S[i] == T[j]? f(i - 1, j - 1) : 0 Where f(i, j) is the number of distinct sub-sequence for T[0:j] in S[0:i].
          數組初始情況是第一列全部是1,代表T字符串是空串,S和自己做匹配。實現代碼如下:
           1 public class DistinctSubsequences {
           2     public int numDistinct(String S, String T) {
           3         int[][] f = new int[S.length() + 1][T.length() + 1];
           4         for (int k = 0; k < S.length(); k++)
           5             f[k][0] = 1;
           6         for (int i = 1; i <= S.length(); i++) {
           7             for (int j = 1; j <= T.length(); j++) {
           8                 if (S.charAt(i - 1) == T.charAt(j - 1)) {
           9                     f[i][j] += f[i - 1][j] + f[i - 1][j - 1];
          10                 } else {
          11                     f[i][j] += f[i - 1][j];
          12                 }
          13             }
          14         }
          15         return f[S.length()][T.length()];
          16     }
          17 }

          Edit Distance
          Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.)
          You have the following 3 operations permitted on a word:
          a) Insert a character
          b) Delete a character
          c) Replace a character

           1 public class EditDistance {
           2     public int minDistance(String word1, String word2) {
           3         if (word1.length() == 0 || word2.length() == 0)
           4             return word1.length() == 0 ? word2.length() : word1.length();
           5         int[][] arr = new int[word2.length() + 1][word1.length() + 1];
           6         for (int i = 0; i <= word1.length(); i++) {
           7             arr[0][i] = i;
           8         }
           9         for (int j = 0; j <= word2.length(); j++) {
          10             arr[j][0] = j;
          11         }
          12         for (int i = 0; i < word1.length(); i++) {
          13             for (int j = 0; j < word2.length(); j++) {
          14                 if (word1.charAt(i) == word2.charAt(j)) {
          15                     arr[j + 1][i + 1] = arr[j][i];
          16                 } else {
          17                     int dis = Math.min(arr[j][i + 1], arr[j + 1][i]);
          18                     arr[j + 1][i + 1] = Math.min(arr[j][i], dis) + 1;
          19                 }
          20             }
          21         }
          22         return arr[word2.length()][word1.length()];
          23     }
          24 }
          posted @ 2013-12-31 10:21 Meng Lee 閱讀(244) | 評論 (0)編輯 收藏

          給定一個無序的整數數組,怎么找到第一個大于0,并且不在此數組的整數。比如[1,2,0] 返回 3, [3,4,-1,1] 返回 2。最好能O(1)空間和O(n)時間。
           1 public class Solution {
           2     public int findMissedNumber(int[] nums) {
           3         for (int i = 0; i < nums.length; i++) {
           4             if (nums[i] > 0 && nums[i] - 1 != i && nums[i] != nums[nums[i] - 1]) {
           5                 int tmp = nums[nums[i] - 1];
           6                 nums[nums[i] - 1] = nums[i];
           7                 nums[i] = tmp;
           8                 i--;
           9             }
          10         }
          11         for (int j = 0; j < nums.length; j++) {
          12             if (nums[j] - 1 != j) return j + 1;
          13         }
          14         return nums.length + 1;
          15     }
          16 }
          posted @ 2013-12-28 15:31 Meng Lee 閱讀(151) | 評論 (0)編輯 收藏

          3個字符串a,b,c。判斷c是否是a和b的interleave,也就是c中應該有a,b中所有字 符,并且c中字符順序和a,b中一樣。比如,
          1. a = "ef" b = "gh" c = "egfh" return true
          2. a = "ef" b = "gh" c = "ehgf" return false

          分析:
          這個題目中,并沒有說明a和b中是否有相同的字符,這個直接影響了最終的解法。所以,大家在面試的過程中,要和面試官進行交互,弄清楚之后再動手。a和b中不含有相同字符的情況很簡單,這里略去。下面給出a和b中包含相同字符的動態規劃的解法。

           1 public class Solution {
           2     public boolean isInterleaved(String a, String b, String c) {
           3         int lengthA = a.length();
           4         int lengthB = b.length();
           5         int lengthC = c.length();
           6         if (lengthA + lengthB != lengthC)
           7             return false;
           8         boolean[][] map = new boolean[lengthB + 1][lengthA + 1];
           9         map[0][0] = true;
          10         for (int m = 1; m < lengthA; m++) {
          11             map[0][m] = (a.charAt(m - 1) == c.charAt(m - 1) && map[0][m - 1]);
          12         }
          13         for (int n = 1; n < lengthB; n++) {
          14             map[n][0] = (b.charAt(n - 1) == c.charAt(n - 1) && map[n - 1][0]);
          15         }
          16         for (int i = 1; i <= lengthB; i++) {
          17             for (int j = 1; j <= lengthA; j++) {
          18                 map[i][j] = (c.charAt(i + j - 1) == b.charAt(i - 1) && map[i - 1][j])
          19                         || (c.charAt(i + j - 1) == a.charAt(j - 1) && map[i][j - 1]);
          20             }
          21         }
          22         return map[lengthB][lengthA];
          23     }
          24 }


          posted @ 2013-12-28 14:29 Meng Lee 閱讀(163) | 評論 (0)編輯 收藏

          刪除字符串中的“b”和“ac”,需要滿足如下的條件:
          1. 字符串只能遍歷一次
          2. 不能夠實用額外的空間

          例如:
          1. acbac   ==>  ""
          2. aaac    ==>  aa
          3. ababac  ==>   aa
          4. bbbbd   ==>   d
          5. aaccac  ==> ""

           1 public class Solution {
           2     public String deleteChars(String s) {
           3         StringBuffer sb = new StringBuffer(s);
           4         int fast = 0, slow = -1;
           5         int length = s.length();
           6         while (fast < length) {
           7             if (sb.charAt(fast) == 'b') {
           8                 fast++;
           9             } else if (fast < length - 1 && sb.charAt(fast) == 'a' && sb.charAt(fast + 1) == 'c') {
          10                 fast += 2;
          11             } else {
          12                 sb.setCharAt(++slow, sb.charAt(fast++));
          13                 if (slow > 0 && sb.charAt(slow - 1) == 'a' && sb.charAt(slow) == 'c') {
          14                     slow -= 2;
          15                 }
          16             }
          17         }
          18         return sb.substring(0, slow + 1);
          19     }
          20 }


          posted @ 2013-12-28 11:02 Meng Lee 閱讀(114) | 評論 (0)編輯 收藏

          對一個字符串按照回文進行分割,例如aba|b|bbabb|a|b|aba就是字符串ababbbabbababa的一個回文分割,每一個字串都是一個回文。請找到可以分割的最少的字串數。例如:
          1. ababbbabbababa最少4個字符串,分割三次:a|babbbab|b|ababa
          2. 如果字符串整體是回文,則需要0次分割,最少1個字符串

          分析:
          遞歸方程為:f(i) = MIN(f(j - 1) + 1), map[j][i] == true, 0<=j<i,其中f(i)為以第i個字符結尾的字符串的最小切割次數,map數組用來記錄s[i][j]是否是對稱的。實現代碼如下:
           1 public class Solution {
           2     public int minPalindromePartition(String s) {
           3         int length = s.length();
           4         boolean[][] map = new boolean[length][length];
           5         int[] record = new int[length];
           6         for (int k = 0; k < length; k++) {
           7             record[k] = k;
           8         }
           9         for (int offset = 0; offset < length; offset++) {
          10             for (int i = 0, j = i + offset; i < length - offset; i++, j++) {
          11                 if (i == j || (s.charAt(i) == s.charAt(j) && (j - i == 1 || map[i + 1][j - 1]))) {
          12                     map[i][j] = true;
          13                 }
          14             }
          15         }
          16         for (int i = 1; i < length; i++) {
          17             for (int j = 0; j < i; j++) {
          18                 if (map[j][i]) {
          19                     if (j > 0) {
          20                         record[i] = Math.min(record[i], record[j - 1] + 1);
          21                     } else {
          22                         record[i] = 0;
          23                     }
          24                 }
          25             }
          26         }
          27         return record[length - 1];
          28     }
          29 }
          posted @ 2013-12-27 16:06 Meng Lee 閱讀(141) | 評論 (0)編輯 收藏

          求二叉搜索樹的中序后繼節點

          分析:
          1. 如果目標節點的右子樹不為空,則返回右子樹的最小節點;
          2. 如果目標節點的右子樹為空,則從根節點開始遍歷。
          實現代碼如下:
           1 public class Solution {
           2     public TreeNode inOrderSuccessor(TreeNode root, TreeNode target) {
           3         if (target == nullreturn null;
           4         if (target.right != nullreturn minValue(target.right);
           5         TreeNode succ = null;
           6         while (root != null) {
           7             if (target.val < root.val) {
           8                 succ = root;
           9                 root = root.left;
          10             } else if (target.val > root.val) {
          11                 root = root.right;
          12             } else {
          13                 break;
          14             }
          15         }
          16         return succ;
          17     }
          18 
          19     private TreeNode minValue(TreeNode root) {
          20         while (root.left != null) {
          21             root = root.left;
          22         }
          23         return root;
          24     }
          25 }
          posted @ 2013-12-27 11:06 Meng Lee 閱讀(208) | 評論 (0)編輯 收藏

          最少插入字符

          給定字符串,可以通過插入字符,使其變為回文。求最少插入字符的數量。例如:
          1. ab最少插入1個字符,變為bab
          2. aa最少插入0個字符
          3. abcd最少插入3個字符,dcbabcd

          分析
              這個題目的分析思路,和前面兩期是非常相似的:給出遞歸的解法,發現重復的子問題,改進為動態規劃的解法,這是一個分析的過程,待同學們比較熟悉時候,可以直接給出動態規劃的解決方案,就很好了。
              這個題目,遞歸該如何解呢?給定一個字符串str,長度為n,怎么插入最少的字符,是的字符串變為回文呢?插入最少的字符,就是要盡量利用原來的字符,在原字符串str中,盡量利用更多能夠匹配的字符。怎么對這個問題進行分解呢?考慮str字符串整體:
              1. 如果str[0]==str[n-1],則問題轉變為求str[1,n-2],插入最少字符,得到回文
              2. 如果str[0]!=str[n-1],則需要插入一個字符要么和str[0]相同,要么和str[n-1]相同,
              3. 如果和str[0],則轉變為str[1,n-1],插入最少字符,得到回文
              4. 如果和str[n-1],則轉變為str[0,n-2],插入最少字符,得到回文
              上面的第2種情況中,需要取兩個值最小值。則完成了問題的分解,并且,基本情況也分析完全,則有遞歸式為:
              fmi(str, l, h) = (str[l] == str[h]) ? fmi(str, l+1, h-1) : (min(fmi(str, i+1, h), fmi(str,l, h-1))+1)
              通過上面的式子,有經驗的、熟練的同學,很直接的就能看出來,存在重復的子問題,這就意味著,我們可以講子問題的解緩存使用。如果,沒有直接能夠看出來的同學們,還是可以按照我們之前的方法,把遞歸樹畫出來吧,那樣更加一目了然。
              那么,這個題目該如何用動態規劃的解決呢?如何重復利用子問題的解呢?似乎有些不那么直接。但其實也是于規律可循的。上面的遞歸式,是從字符串的兩 邊,想中間移動遞歸,根據動態規劃解決問題的思想,我們先解決子問題,再重復利用子問題,就是要從內向外解決,大家還記得回文子串判斷的那個題目么,動態 規劃解法的外層循環是子串的長度,這個題目也是類似的。示例代碼如下:
           1 public class Solution {
           2     public int constructPalindrome(String s) {
           3         int length = s.length();
           4         int[][] map = new int[length][length];
           5         for (int offset = 1; offset < length; offset++) {
           6             for (int i = 0, j = offset; i < length - offset; i++, j++) {
           7                 if (i == j - 1) {
           8                     if (s.charAt(i) != s.charAt(j)) {
           9                         map[i][j] = 1;
          10                     }
          11                 } else {
          12                     if (s.charAt(i) != s.charAt(j)) {
          13                         map[i][j] = Math.min(map[i][j - 1], map[i + 1][j]) + 1;
          14                     } else {
          15                         map[i][j] = map[i + 1][j - 1];
          16                     }
          17                 }
          18             }
          19         }
          20         return map[0][length - 1];
          21     }
          22 }
          posted @ 2013-12-26 16:53 Meng Lee 閱讀(172) | 評論 (0)編輯 收藏

          1、給定一組區間,表示為[start,end],請給出方法,將有重疊的區間進行合并。例如:
          給定:[1,3],[2,6],[8,10],[15,18],
          合并:[1,6],[8,10],[15,18].
          分析:題目很直觀,首先把區間遞增排序,然后從頭合并,合并時觀察當前區間的start是否小于或等于前一個區間的end。代碼如下:
           1 public class MergeIntervals {
           2     public class IntervalCmp implements Comparator<Interval> {
           3         @Override
           4         public int compare(Interval i1, Interval i2) {
           5             if (i1.start < i2.start) return -1;
           6             if (i1.start == i2.start && i1.end <= i2.end) return -1;
           7             return 1;
           8         }
           9     }
          10     
          11     public ArrayList<Interval> merge(ArrayList<Interval> intervals) {
          12         ArrayList<Interval> ret = new ArrayList<Interval>();
          13         if (intervals.size() == 0) return ret;
          14         Interval[] arr = new Interval[intervals.size()];
          15         intervals.toArray(arr);
          16         Arrays.sort(arr, new IntervalCmp());
          17         int start = arr[0].start;
          18         int end = arr[0].end;
          19         for (int i = 0; i < arr.length; i++) {
          20             if (arr[i].start <= end) {
          21                 end = Math.max(end, arr[i].end);
          22             } else {
          23                 ret.add(new Interval(start, end));
          24                 start = arr[i].start;
          25                 end = arr[i].end;
          26             }
          27         }
          28         ret.add(new Interval(start, end));
          29         return ret;
          30     }
          31 }
          2、給定的一組區間,將區間中的存在的任意區間的父區間刪除,例如:
          給定:[1,2] [1,3] [1,4] [5,9] [6,8]
          刪除后:[1,2] [6,8]
          分析:此題暴力的解法的復雜度為O(N^2)。受上一題排序的啟發,是否有好一點的思路呢?
          我們可以按照start遞增排序,若start相等,則按照end遞減排序。考慮排序后的第i-1 和第i個區間,由于start是遞增的,所以第i-1個區間的start肯定小于等于第i個區間的start。若第i-1個區間的end大于等于第i個區間的end,則第i-1個區間就成為第i個區間的父區間了。

          按照這個思路,可以試著在排序之后逆向順序處理每一個區間。假設當前處理第i個區間,如前所述,若第i-1個區間的end大于等于第i個區間的end,則第i-1個區間成為第i個區間的父區間,可以保留第i個區間,將第i-1個區間刪除。由于第i-1個區間是第i個區間的父區間,所以第i-1個區間的父區間也是第i個區間的父區間,這種情形下刪掉第i-1個區間,后續不會漏刪第i-1個區間的父區間。若第i-1個區間的end小于第i個區間的end,則可以跳過第i個區間,開始處理第i-1個區間。因為按照這種處理的方法,在處理到第i個區間時,該區間不會是任何區間的父區間(若是父區間已經被如前所述的方法刪除了)。而且,在這種情形下,后續可能出現的第i個區間的父區間會是第i-1個區間的父區間,所以也不會漏掉第i個區間的父區間。所以排序之后逆向處理,只需要O(N)的時間,就可以解決這道問題。整體的時間復雜度為O(nlogn)。
           1 public class Solution {
           2     public class IntervalCmp implements Comparator<Interval> {
           3         @Override
           4         public int compare(Interval i1, Interval i2) {
           5             if (i1.start < i2.start) return -1;
           6             if (i1.start == i2.start && i1.end >= i2.end) return -1;
           7             return 1;
           8         }
           9     }
          10     
          11     public ArrayList<Interval> merge(ArrayList<Interval> intervals) {
          12         ArrayList<Interval> ret = new ArrayList<Interval>();
          13         if (intervals.size() == 0) return ret;
          14         Interval[] arr = new Interval[intervals.size()];
          15         intervals.toArray(arr);
          16         Arrays.sort(arr, new IntervalCmp());
          17         int start = arr[arr.length - 1].start;
          18         int end = arr[arr.length - 1].end;
          19         for (int i = arr.length - 2; i >= 0; i--) {
          20             if (arr[i].end < end) {
          21                 ret.add(new Interval(start, end));
          22                 start = arr[i].start;
          23                 end = arr[i].end;
          24             }
          25         }
          26         ret.add(new Interval(start, end));
          27         return ret;
          28     }
          29 }
          posted @ 2013-12-26 14:47 Meng Lee 閱讀(1797) | 評論 (0)編輯 收藏

          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.

          本題本來的想法是用遞歸做,實現代碼如下:
           1 public class Solution {
           2     public int minimumTotal(ArrayList<ArrayList<Integer>> triangle) {
           3         int row = triangle.size();
           4         return findMinPath(triangle, 0, 0, row);
           5     }
           6 
           7     private int findMinPath(ArrayList<ArrayList<Integer>> triangle, int row,
           8             int col, int totalRow) {
           9         if (row == totalRow - 1) {
          10             return triangle.get(row).get(col);
          11         } else {
          12             return triangle.get(row).get(col) + Math.min(findMinPath(triangle, row + 1, col, totalRow), findMinPath(triangle, row + 1, col + 1, totalRow));
          13         }
          14     }
          15 }
          提交之后發現超時,于是考慮到可能是遞歸的開銷問題,考慮用迭代解題。實現如下:
           1 public class Triangle {
           2     public int minimumTotal(ArrayList<ArrayList<Integer>> triangle) {
           3         int n = triangle.size() - 1;
           4         int[] path = new int[triangle.size()];
           5         for (int o = 0; o < triangle.get(n).size(); o++) {
           6             path[o] = triangle.get(n).get(o);
           7         }
           8         for (int i = triangle.size() - 2; i >= 0; i--) {
           9             for (int j = 0, t = 0; j < triangle.get(i + 1).size() - 1; j++, t++) {
          10                 path[t] = triangle.get(i).get(t)
          11                         + Math.min(path[j], path[j + 1]);
          12             }
          13         }
          14         return path[0];
          15     }
          16 }
          這個解法的核心是從葉節點自底向上構造解空間。
          posted @ 2013-12-25 11:31 Meng Lee 閱讀(155) | 評論 (0)編輯 收藏

          Subsets的解法是從空集開始,依次取每一個元素與子集中的每個集合做并操作。實現代碼如下:

           1 public class Subsets {
           2     public ArrayList<ArrayList<Integer>> subsets(int[] S) {
           3         Arrays.sort(S);
           4         ArrayList<ArrayList<Integer>> subsets = new ArrayList<ArrayList<Integer>>();
           5         subsets.add(new ArrayList<Integer>());
           6         for (int i = 0; i < S.length; i++) {
           7             int size = subsets.size();
           8             for (int j = 0; j < size; j++) {
           9                 ArrayList<Integer> subset = new ArrayList<Integer>(
          10                         subsets.get(j));
          11                 subset.add(S[i]);
          12                 subsets.add(subset);
          13             }
          14         }
          15         return subsets;
          16     }
          17 }

          Gray Code的算法是初始時集合中只有{0, 1}兩個元素,此后在每個元素的前面附加一個1。實現代碼如下:

           1 public class GrayCode {
           2     public ArrayList<Integer> grayCode(int n) {
           3         ArrayList<Integer> result = new ArrayList<Integer>();
           4         if (n == 0) {
           5             result.add(0);
           6             return result;
           7         }
           8         ;
           9         result.add(0);
          10         result.add(1);
          11         for (int i = 1; i < n; i++) {
          12             ArrayList<Integer> tmp = new ArrayList<Integer>(result);
          13             Integer a = 1 << i;
          14             for (int k = result.size() - 1; k >= 0; k--) {
          15                 tmp.add(result.get(k) + a);
          16             }
          17             result = tmp;
          18         }
          19         return result;
          20     }
          21 }

          posted @ 2013-12-24 12:06 Meng Lee 閱讀(252) | 評論 (0)編輯 收藏

          僅列出標題
          共4頁: 上一頁 1 2 3 4 下一頁 
          主站蜘蛛池模板: 荆州市| 且末县| 黑龙江省| 台山市| 汾阳市| 阳谷县| 兴海县| 牡丹江市| 阳原县| 孙吴县| 横峰县| 桂林市| 江城| 五河县| 宿松县| 陵川县| 新泰市| 手游| 泰兴市| 左云县| 襄汾县| 昌都县| 西畴县| 福鼎市| 鄂托克前旗| 吉安市| 黑龙江省| 镇江市| 长顺县| 关岭| 宁德市| 庆阳市| 陆河县| 乳源| 都江堰市| 英吉沙县| 丽水市| 平和县| 浪卡子县| SHOW| 黄浦区|