以下从Java角度解释面试常见的算法和数据结构:字符串,链表,树,图,排序,递归 vs. 迭代,动态规划,位操作,概率问题,排列组合,以及一些需要寻找规律的题目。
1. 字符串和数组
字符串和数组是最常见的面试题目类型,应当分配最大的时间。关于字符串,首先需要注意的是和C++不同,Java字符串不是char数组。没有IDE代码自动补全功能,应该记住下面的这些常用的方法。
toCharArray() //获得字符串对应的char数组
Arrays.sort() //数组排序
Arrays.toString(char[] a) //数组转成字符串
charAt(int x) //获得某个索引处的字符
length() //字符串长度
length //数组大小
substring(int beginIndex)
substring(int beginIndex, int endIndex)
Integer.valueOf() //string to integer
String.valueOf() /integer to string
字符串和数组本身很简单,但是相关的题目需要更复杂的算法来解决。比如说动态规划,搜索,等等。
经典题目:
1) Evaluate Reverse Polish Notation
The problem:
Evaluate the value of an arithmetic expression in Reverse Polish Notation.
Valid operators are +, -, *, /. Each operand may be an integer or another expression.
Some examples:
["2", "1", "+", "3", "*"] -> ((2 + 1) * 3) -> 9
["4", "13", "5", "/", "+"] -> (4 + (13 / 5)) -> 6
思路:
This problem is simple. After understanding the problem, we should quickly realize that this problem can be solved by using a stack. We can loop through each element in the given array. When it is a number, push it to the stack. When it is an operator, pop two numbers from the stack, do the calculation, and push back the result.
解法1:
- public class Test {
- public static void main(String[] args) throws IOException {
- String[] tokens = new String[] { "2", "1", "+", "3", "*" };
- System.out.println(evalRPN(tokens));
- }
- public static int evalRPN(String[] tokens) {
- int returnValue = 0;
- String operators = "+-*/";
- Stack<String> stack = new Stack<String>();
- for (String t : tokens) {
- if (!operators.contains(t)) {
- stack.push(t);
- } else {
- int a = Integer.valueOf(stack.pop());
- int b = Integer.valueOf(stack.pop());
- switch (t) {
- case "+":
- stack.push(String.valueOf(a + b));
- break;
- case "-":
- stack.push(String.valueOf(b - a));
- break;
- case "*":
- stack.push(String.valueOf(a * b));
- break;
- case "/":
- stack.push(String.valueOf(b / a));
- break;
- }
- }
- }
- returnValue = Integer.valueOf(stack.pop());
- return returnValue;
- }
- }
解法2:
- public class Solution {
- public int evalRPN(String[] tokens) {
- int returnValue = 0;
- String operators = "+-*/";
- Stack<String> stack = new Stack<String>();
- for(String t : tokens){
- if(!operators.contains(t)){
- stack.push(t);
- }else{
- int a = Integer.valueOf(stack.pop());
- int b = Integer.valueOf(stack.pop());
- int index = operators.indexOf(t);
- switch(index){
- case 0:
- stack.push(String.valueOf(a+b));
- break;
- case 1:
- stack.push(String.valueOf(b-a));
- break;
- case 2:
- stack.push(String.valueOf(a*b));
- break;
- case 3:
- stack.push(String.valueOf(b/a));
- break;
- }
- }
- }
- returnValue = Integer.valueOf(stack.pop());
- return returnValue;
- }
- }
2) Longest Palindromic Substring
题目来源:
Finding the longest palindromic substring is a classic problem of coding interview. In this post, I will summarize 3 different solutions for this problem.
解法一:暴力算法
Naively, we can simply examine every substring and check if it is palindromic. The time complexity is O(n^3). If this is submitted to LeetCode onlinejudge, an error message will be returned - "Time Limit Exceeded". Therefore, this approach is just a start, we need a better algorithm.
- public static String longestPalindrome1(String s) {
- int maxPalinLength = 0;
- String longestPalindrome = null;
- int length = s.length();
- // check all possible sub strings
- for (int i = 0; i < length; i++) {
- for (int j = i + 1; j < length; j++) {
- int len = j - i;
- String curr = s.substring(i, j + 1);
- if (isPalindrome(curr)) {
- if (len > maxPalinLength) {
- longestPalindrome = curr;
- maxPalinLength = len;
- }
- }
- }
- }
- return longestPalindrome;
- }
- public static boolean isPalindrome(String s) {
- for (int i = 0; i < s.length() - 1; i++) {
- if (s.charAt(i) != s.charAt(s.length() - 1 - i)) {
- return false;
- }
- }
- return true;
- }
解法二: 简单算法
- public String longestPalindrome(String s) {
- if (s.isEmpty()) {
- return null;
- }
- if (s.length() == 1) {
- return s;
- }
- String longest = s.substring(0, 1);
- for (int i = 0; i < s.length(); i++) {
- // get longest palindrome with center of i
- String tmp = helper(s, i, i);
- if (tmp.length() > longest.length()) {
- longest = tmp;
- }
- // get longest palindrome with center of i, i+1
- tmp = helper(s, i, i + 1);
- if (tmp.length() > longest.length()) {
- longest = tmp;
- }
- }
- return longest;
- }
- // Given a center, either one letter or two letter,
- // Find longest palindrome
- public String helper(String s, int begin, int end) {
- while (begin >= 0 && end <= s.length() - 1 && s.charAt(begin) == s.charAt(end)) {
- begin--;
- end++;
- }
- return s.substring(begin + 1, end);
- }
题目:
Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separated sequence of one or more dictionary words.
For example, given
s = "leetcode",
dict = ["leet", "code"].
Return true because "leetcode" can be segmented as "leet code".
解法1:暴力
- public class Solution {
- public boolean wordBreak(String s, Set<String> dict) {
- return wordBreakHelper(s, dict, 0);
- }
- public boolean wordBreakHelper(String s, Set<String> dict, int start){
- if(start == s.length())
- return true;
- for(String a: dict){
- int len = a.length();
- int end = start+len;
- //end index should be <= string length
- if(end > s.length())
- continue;
- if(s.substring(start, start+len).equals(a))
- if(wordBreakHelper(s, dict, start+len))
- return true;
- }
- return false;
- }
- }
Time: O(n^2)
解法2: 动态规划
The key to solve this problem by using dynamic programming approach:
- Define an array t[] such that t[i]==true => 0-(i-1) can be segmented using dictionary
- Initial state t[0] == true
- public class Solution {
- public boolean wordBreak(String s, Set<String> dict) {
- boolean[] t = new boolean[s.length()+1];
- t[0] = true; //set first to be true, why?
- //Because we need initial state
- for(int i=0; i<s.length(); i++){
- //should continue from match position
- if(!t[i])
- continue;
- for(String a: dict){
- int len = a.length();
- int end = i + len;
- if(end > s.length())
- continue;
- if(t[end]) continue;
- if(s.substring(i, end).equals(a)){
- t[end] = true;
- }
- }
- }
- return t[s.length()];
- }
- }
Time: O(string length * dict size)
One tricky part of this solution is the case:
INPUT: "programcreek", ["programcree","program","creek"].解法3: 正则表达式
- public static void main(String[] args) {
- HashSet<String> dict = new HashSet<String>();
- dict.add("go");
- dict.add("goal");
- dict.add("goals");
- dict.add("special");
- StringBuilder sb = new StringBuilder();
- for(String s: dict){
- sb.append(s + "|");
- }
- String pattern = sb.toString().substring(0, sb.length()-1);
- pattern = "("+pattern+")*";
- Pattern p = Pattern.compile(pattern);
- Matcher m = p.matcher("goalspecial");
- if(m.matches()){
- System.out.println("match");
- }
- }
表达式 |
说明 |
| |
多个子表达式之间取“或”的关系 |
* |
表达式匹配0次或任意多次,相当于{0,} |
题目:
Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that:
Only one letter can be changed at a time
Each intermediate word must exist in the dictionary
For example,
Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]
As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog", the program should return its length 5.
Note:
Return 0 if there is no such transformation sequence.
All words have the same length.
All words contain only lowercase alphabetic characters.
So we quickly realize that this looks like a tree searching problem for which breath first guarantees the optimal solution.
Assuming we have some words in the dictionary, and the start is "hit" as shown in the diagram below.
We can use two queues to traverse the tree, one stores the nodes, the other stores the step numbers.
Updated on 2/27/2015.
- public int ladderLength(String start, String end, HashSet<String> dict) {
- if (dict.size() == 0)
- return 0;
- dict.add(end);
- LinkedList<String> wordQueue = new LinkedList<String>();
- LinkedList<Integer> distanceQueue = new LinkedList<Integer>();
- wordQueue.add(start);
- distanceQueue.add(1);
- //track the shortest path
- int result = Integer.MAX_VALUE;
- while (!wordQueue.isEmpty()) {
- String currWord = wordQueue.pop();
- Integer currDistance = distanceQueue.pop();
- if (currWord.equals(end)) {
- result = Math.min(result, currDistance);
- }
- for (int i = 0; i < currWord.length(); i++) {
- char[] currCharArr = currWord.toCharArray();
- for (char c = 'a'; c <= 'z'; c++) {
- currCharArr[i] = c;
- String newWord = new String(currCharArr);
- if (dict.contains(newWord)) {
- wordQueue.add(newWord);
- distanceQueue.add(currDistance + 1);
- dict.remove(newWord);
- }
- }
- }
- }
- if (result < Integer.MAX_VALUE)
- return result;
- else
- return 0;
- }
5) Median of Two Sorted Arrays
6) Regular Expression Matching
问题:
Given a collection of intervals, merge all overlapping intervals.思路:
For example,
Given [1,3],[2,6],[8,10],[15,18],
return [1,6],[8,10],[15,18].
The key to solve this problem is defining a Comparator first to sort the arraylist of Intevals. And then merge some intervals.
The take-away message from this problem is utilizing the advantage of sorted list/array.
解法:- class Interval {
- int start;
- int end;
- Interval() {
- start = 0;
- end = 0;
- }
- Interval(int s, int e) {
- start = s;
- end = e;
- }
- }
- public class Solution {
- public ArrayList<Interval> merge(ArrayList<Interval> intervals) {
- if (intervals == null || intervals.size() <= 1)
- return intervals;
- // sort intervals by using self-defined Comparator
- Collections.sort(intervals, new IntervalComparator());
- ArrayList<Interval> result = new ArrayList<Interval>();
- Interval prev = intervals.get(0);
- for (int i = 1; i < intervals.size(); i++) {
- Interval curr = intervals.get(i);
- if (prev.end >= curr.start) {
- // merged case
- Interval merged = new Interval(prev.start, Math.max(prev.end, curr.end));
- prev = merged;
- } else {
- result.add(prev);
- prev = curr;
- }
- }
- result.add(prev);
- return result;
- }
- }
- class IntervalComparator implements Comparator<Interval> {
- public int compare(Interval i1, Interval i2) {
- return i1.start - i2.start;
- }
- }
问题:
Problem:
Given a set of non-overlapping & sorted intervals, insert a new interval into the intervals (merge if necessary).
Example 1:
Given intervals [1,3],[6,9], insert and merge [2,5] in as [1,5],[6,9].
Example 2:
Given [1,2],[3,5],[6,7],[8,10],[12,16], insert and merge [4,9] in as [1,2],[3,10],[12,16].
This is because the new interval [4,9] overlaps with [3,5],[6,7],[8,10].
解法:
- /**
- * Definition for an interval.
- * public class Interval {
- * int start;
- * int end;
- * Interval() { start = 0; end = 0; }
- * Interval(int s, int e) { start = s; end = e; }
- * }
- */
- public class Solution {
- public ArrayList<Interval> insert(ArrayList<Interval> intervals, Interval newInterval) {
- ArrayList<Interval> result = new ArrayList<Interval>();
- for(Interval interval: intervals){
- if(interval.end < newInterval.start){
- result.add(interval);
- }else if(interval.start > newInterval.end){
- result.add(newInterval);
- newInterval = interval;
- }else if(interval.end >= newInterval.start || interval.start <= newInterval.end){
- newInterval = new Interval(Math.min(interval.start, newInterval.start), Math.max(newInterval.end, interval.end));
- }
- }
- result.add(newInterval);
- return result;
- }
- }
题目:
Given an array of integers, find two numbers such that they add up to a specific target number.
The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.
For example:
Input: numbers={2, 7, 11, 15}, target=9解法1:
Output: index1=1, index2=2
- public static int[] twoSum(int[] numbers, int target) {
- int[] ret = new int[2];
- for (int i = 0; i < numbers.length; i++) {
- for (int j = i + 1; j < numbers.length; j++) {
- if (numbers[i] + numbers[j] == target) {
- ret[0] = i + 1;
- ret[1] = j + 1;
- }
- }
- }
- return ret;
- }
解法2:
- public class Solution {
- public int[] twoSum(int[] numbers, int target) {
- HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
- int[] result = new int[2];
- for (int i = 0; i < numbers.length; i++) {
- if (map.containsKey(numbers[i])) {
- int index = map.get(numbers[i]);
- result[0] = index+1 ;
- result[1] = i+1;
- break;
- } else {
- map.put(target - numbers[i], i);
- }
- }
- return result;
- }
- }
题目:
Problem:
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
The solution set must not contain duplicate triplets.
For example, given array S = {-1 0 1 2 -1 -4},解法1:
A solution set is:
(-1, 0, 1)
(-1, -1, 2)
- public class Solution {
- public ArrayList<ArrayList<Integer>> threeSum(int[] num) {
- //sort array
- Arrays.sort(num);
- ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
- ArrayList<Integer> each = new ArrayList<Integer>();
- for(int i=0; i<num.length; i++){
- if(num[i] > 0) break;
- for(int j=i+1; j<num.length; j++){
- if(num[i] + num[j] > 0 && num[j] > 0) break;
- for(int k=j+1; k<num.length; k++){
- if(num[i] + num[j] + num[k] == 0) {
- each.add(num[i]);
- each.add(num[j]);
- each.add(num[k]);
- result.add(each);
- each.clear();
- }
- }
- }
- }
- return result;
- }
- }
解法2:
- public ArrayList<ArrayList<Integer>> threeSum(int[] num) {
- ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
- if (num.length < 3)
- return result;
- // sort array
- Arrays.sort(num);
- for (int i = 0; i < num.length - 2; i++) {
- // //avoid duplicate solutions
- if (i == 0 || num[i] > num[i - 1]) {
- int negate = -num[i];
- int start = i + 1;
- int end = num.length - 1;
- while (start < end) {
- //case 1
- if (num[start] + num[end] == negate) {
- ArrayList<Integer> temp = new ArrayList<Integer>();
- temp.add(num[i]);
- temp.add(num[start]);
- temp.add(num[end]);
- result.add(temp);
- start++;
- end--;
- //avoid duplicate solutions
- while (start < end && num[end] == num[end + 1])
- end--;
- while (start < end && num[start] == num[start - 1])
- start++;
- //case 2
- } else if (num[start] + num[end] < negate) {
- start++;
- //case 3
- } else {
- end--;
- }
- }
- }
- }
- return result;
- }
题目:
Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
Note:
Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)
The solution set must not contain duplicate quadruplets.
For example, given array S = {1 0 -1 0 -2 2}, and target = 0.解法:
A solution set is:
(-1, 0, 0, 1)
(-2, -1, 1, 2)
(-2, 0, 0, 2)
- public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
- Arrays.sort(num);
- HashSet<ArrayList<Integer>> hashSet = new HashSet<ArrayList<Integer>>();
- ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
- for (int i = 0; i < num.length; i++) {
- for (int j = i + 1; j < num.length; j++) {
- int k = j + 1;
- int l = num.length - 1;
- while (k < l) {
- int sum = num[i] + num[j] + num[k] + num[l];
- if (sum > target) {
- l--;
- } else if (sum < target) {
- k++;
- } else if (sum == target) {
- ArrayList<Integer> temp = new ArrayList<Integer>();
- temp.add(num[i]);
- temp.add(num[j]);
- temp.add(num[k]);
- temp.add(num[l]);
- if (!hashSet.contains(temp)) {
- hashSet.add(temp);
- result.add(temp);
- }
- k++;
- l--;
- }
- }
- }
- }
- return result;
- }
Here is the hashCode method of ArrayList. It makes sure that if all elements of two lists are the same, then the hash code of the two lists will be the same. Since each element in the ArrayList is Integer, same integer has same hash code.
- int hashCode = 1;
- Iterator<E> i = list.iterator();
- while (i.hasNext()) {
- E obj = i.next();
- hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
- }
题目来源:
Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution. For example, given array S = {-1 2 1 -4}, and target = 1. The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
解法:
- public class Solution {
- public int threeSumClosest(int[] num, int target) {
- int min = Integer.MAX_VALUE;
- int result = 0;
- Arrays.sort(num);
- for (int i = 0; i < num.length; i++) {
- int j = i + 1;
- int k = num.length - 1;
- while (j < k) {
- int sum = num[i] + num[j] + num[k];
- int diff = Math.abs(sum - target);
- if(diff == 0) return 0;
- if (diff < min) {
- min = diff;
- result = sum;
- }
- if (sum <= target) {
- j++;
- } else {
- k--;
- }
- }
- }
- return result;
- }
- }
题目来源:
Implement atoi to convert a string to an integer.
Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases.
Notes: It is intended for this problem to be specified vaguely (ie, no given input specs). You are responsible to gather all the input requirements up front.
Thoughts for This Problem
The vague description give us space to consider different cases.
1. null or empty string解法:
2. white spaces
3. +/- sign
4. calculate real value
5. handle min & max
- public int atoi(String str) {
- if (str == null || str.length() < 1)
- return 0;
- // trim white spaces
- str = str.trim();
- char flag = '+';
- // check negative or positive
- int i = 0;
- if (str.charAt(0) == '-') {
- flag = '-';
- i++;
- } else if (str.charAt(0) == '+') {
- i++;
- }
- // use double to store result
- double result = 0;
- // calculate value
- while (str.length() > i && str.charAt(i) >= '0' && str.charAt(i) <= '9') {
- result = result * 10 + (str.charAt(i) - '0');
- i++;
- }
- if (flag == '-')
- result = -result;
- // handle max and min
- if (result > Integer.MAX_VALUE)
- return Integer.MAX_VALUE;
- if (result < Integer.MIN_VALUE)
- return Integer.MIN_VALUE;
- return (int) result;
- }
题目来源:
Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
The brackets must close in the correct order, "()" and "()[]{}" are all valid but "(]" and "([)]" are not.
解法1:- public static boolean isValid(String s) {
- HashMap<Character, Character> map = new HashMap<Character, Character>();
- map.put('(', ')');
- map.put('[', ']');
- map.put('{', '}');
- Stack<Character> stack = new Stack<Character>();
- for (int i = 0; i < s.length(); i++) {
- char curr = s.charAt(i);
- if (map.keySet().contains(curr)) {
- stack.push(curr);
- } else if (map.values().contains(curr)) {
- if (!stack.empty() && map.get(stack.peek()) == curr) {
- stack.pop();
- } else {
- return false;
- }
- }
- }
- return stack.empty();
- }
解法2:
- public static boolean isValid(String s) {
- char[] charArray = s.toCharArray();
- HashMap<Character, Character> map = new HashMap<Character, Character>();
- map.put('(', ')');
- map.put('[', ']');
- map.put('{', '}');
- Stack<Character> stack = new Stack<Character>();
- for (Character c : charArray) {
- if (map.keySet().contains(c)) {
- stack.push(c);
- } else if (map.values().contains(c)) {
- if (!stack.isEmpty() && map.get(stack.peek()) == c) {
- stack.pop();
- } else {
- return false;
- }
- }
- }
- return stack.isEmpty();
- }
题目来源:
Implement strStr().
Returns a pointer to the first occurrence of needle in haystack, or null if needle is not part of haystack.
思路:First, need to understand the problem correctly, the pointer simply means a sub string.
Second, make sure the loop does not exceed the boundaries of two strings.
解法:
- public String strStr(String haystack, String needle) {
- int needleLen = needle.length();
- int haystackLen = haystack.length();
- if (needleLen == haystackLen && needleLen == 0)
- return "";
- if (needleLen == 0)
- return haystack;
- for (int i = 0; i < haystackLen; i++) {
- // make sure in boundary of needle
- if (haystackLen - i + 1 < needleLen)
- return null;
- int k = i;
- int j = 0;
- while (j < needleLen && k < haystackLen && needle.charAt(j) == haystack.charAt(k)) {
- j++;
- k++;
- if (j == needleLen)
- return haystack.substring(i);
- }
- }
- return null;
- }
From Tia:
You have to check if a String == null before call length(), otherwise it will throw NullPointerException.
题目来源:
Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order. You may assume no duplicates in the array.
Here are few examples.
[1,3,5,6], 5 -> 2解法1:
[1,3,5,6], 2 -> 1
[1,3,5,6], 7 -> 4
[1,3,5,6], 0 -> 0
- public class Solution {
- public int searchInsert(int[] A, int target) {
- if(A==null) return 0;
- if(target <= A[0]) return 0;
- for(int i=0; i<A.length-1; i++){
- if(target > A[i] && target <= A[i+1]){
- return i+1;
- }
- }
- return A.length;
- }
- }
解法2:
- public class Solution {
- public int searchInsert(int[] A, int target) {
- if(A==null||A.length==0)
- return 0;
- return searchInsert(A,target,0,A.length-1);
- }
- public int searchInsert(int[] A, int target, int start, int end){
- int mid=(start+end)/2;
- if(target==A[mid])
- return mid;
- else if(target<A[mid])
- return start<mid?searchInsert(A,target,start,mid-1):start;
- else
- return end>mid?searchInsert(A,target,mid+1,end):(end+1);
- }
- }
17) Longest Consecutive Sequence
问题来源:
Longest Consecutive Sequence Java
思路:Thoughts
Because it requires O(n) complexity, we can not solve the problem by sorting the array first. Sorting takes at least O(nlogn) time.
解法:- public static int longestConsecutive(int[] num) {
- // if array is empty, return 0
- if (num.length == 0) {
- return 0;
- }
- Set<Integer> set = new HashSet<Integer>();
- int max = 1;
- for (int e : num)
- set.add(e);
- for (int e : num) {
- int left = e - 1;
- int right = e + 1;
- int count = 1;
- while (set.contains(left)) {
- count++;
- set.remove(left);
- left--;
- }
- while (set.contains(right)) {
- count++;
- set.remove(right);
- right++;
- }
- max = Math.max(count, max);
- }
- return max;
- }
after an element is checked, it should be removed from the set. Otherwise, time complexity would be O(mn) in which m is the average length of all consecutive sequences.
To clearly see the time complexity, I suggest you use some simple examples and manually execute the program. For example, given an array {1,2,4,5,3}
, the program time is m. m is the length of longest consecutive sequence.
We do have an extreme case here: If n is number of elements, m is average length of consecutive sequence, and m==n, then the time complexity is O(n^2). The reason is that in this case, no element is removed from the set each time. You can use this array to get the point: {1,3,5,7,9}.
题目来源:
Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.
For example, "Red rum, sir, is murder"
is a palindrome, while "Programcreek is awesome"
is not.
Note:
Have you consider that the string might be empty? This is a good question to ask during an interview.
For the purpose of this problem, we define empty string as valid palindrome.
思路:
From start and end loop though the string, i.e., char array. If it is not alpha or number, increase or decrease pointers. Compare the alpha and numeric characters. The solution below is pretty straightforward.
解法1:
- public class Solution {
- public boolean isPalindrome(String s) {
- if(s == null) return false;
- if(s.length() < 2) return true;
- char[] charArray = s.toCharArray();
- int len = s.length();
- int i=0;
- int j=len-1;
- while(i<j){
- char left, right;
- while(i<len-1 && !isAlpha(left) && !isNum(left)){
- i++;
- left = charArray[i];
- }
- while(j>0 && !isAlpha(right) && !isNum(right)){
- j--;
- right = charArray[j];
- }
- if(i >= j)
- break;
- left = charArray[i];
- right = charArray[j];
- if(!isSame(left, right)){
- return false;
- }
- i++;
- j--;
- }
- return true;
- }
- public boolean isAlpha(char a){
- if((a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z')){
- return true;
- }else{
- return false;
- }
- }
- public boolean isNum(char a){
- if(a >= '0' && a <= '9'){
- return true;
- }else{
- return false;
- }
- }
- public boolean isSame(char a, char b){
- if(isNum(a) && isNum(b)){
- return a == b;
- }else if(Character.toLowerCase(a) == Character.toLowerCase(b)){
- return true;
- }else{
- return false;
- }
- }
- }
解法2:
- public class Solution {
- public boolean isPalindrome(String s) {
- if(s == null) return false;
- if(s.length() < 2) return true;
- char[] charArray = s.toCharArray();
- int len = s.length();
- int i=0;
- int j=len-1;
- while(i<j){
- char left, right;
- while(i<len-1 && !isAlpha(left) && !isNum(left)){
- i++;
- left = charArray[i];
- }
- while(j>0 && !isAlpha(right) && !isNum(right)){
- j--;
- right = charArray[j];
- }
- if(i >= j)
- break;
- left = charArray[i];
- right = charArray[j];
- if(!isSame(left, right)){
- return false;
- }
- i++;
- j--;
- }
- return true;
- }
- public boolean isAlpha(char a){
- if((a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z')){
- return true;
- }else{
- return false;
- }
- }
- public boolean isNum(char a){
- if(a >= '0' && a <= '9'){
- return true;
- }else{
- return false;
- }
- }
- public boolean isSame(char a, char b){
- if(isNum(a) && isNum(b)){
- return a == b;
- }else if(Character.toLowerCase(a) == Character.toLowerCase(b)){
- return true;
- }else{
- return false;
- }
- }
- }
解法3:
- public boolean isPalindrome(String s) {
- s = s.replaceAll("[^a-zA-Z0-9]", "").toLowerCase();
- int len = s.length();
- if (len < 2)
- return true;
- Stack<Character> stack = new Stack<Character>();
- int index = 0;
- while (index < len / 2) {
- stack.push(s.charAt(index));
- index++;
- }
- if (len % 2 == 1)
- index++;
- while (index < len) {
- if (stack.empty())
- return false;
- char temp = stack.pop();
- if (s.charAt(index) != temp)
- return false;
- else
- index++;
- }
- return true;
- }
题目来源:
Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order.
For example, given the following matrix:
[
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]
]
You should return [1,2,3,6,9,8,7,4,5].
解法:If more than one row and column left, it can form a circle and we process the circle. Otherwise, if only one row or column left, we process that column or row ONLY.
- public class Solution {
- public ArrayList<Integer> spiralOrder(int[][] matrix) {
- ArrayList<Integer> result = new ArrayList<Integer>();
- if(matrix == null || matrix.length == 0) return result;
- int m = matrix.length;
- int n = matrix[0].length;
- int x=0;
- int y=0;
- while(m>0 && n>0){
- //if one row/column left, no circle can be formed
- if(m==1){
- for(int i=0; i<n; i++){
- result.add(matrix[x][y++]);
- }
- break;
- }else if(n==1){
- for(int i=0; i<m; i++){
- result.add(matrix[x++][y]);
- }
- break;
- }
- //below, process a circle
- //top - move right
- for(int i=0;i<n-1;i++){
- result.add(matrix[x][y++]);
- }
- //right - move down
- for(int i=0;i<m-1;i++){
- result.add(matrix[x++][y]);
- }
- //bottom - move left
- for(int i=0;i<n-1;i++){
- result.add(matrix[x][y--]);
- }
- //left - move up
- for(int i=0;i<m-1;i++){
- result.add(matrix[x--][y]);
- }
- x++;
- y++;
- m=m-2;
- n=n-2;
- }
- return result;
- }
- }
题目来源:
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has properties:
1) Integers in each row are sorted from left to right. 2) The first integer of each row is greater than the last integer of the previous row.
For example, consider the following matrix:
[
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]
Given target = 3, return true.
解法:This is a typical problem of binary search.
You may try to solve this problem by finding the row first and then the column. There is no need to do that. Because of the matrix's special features, the matrix can be considered as a sorted array. Your goal is to find one element in this sorted array by using binary search.
- public class Solution {
- public boolean searchMatrix(int[][] matrix, int target) {
- if(matrix==null || matrix.length==0 || matrix[0].length==0)
- return false;
- int m = matrix.length;
- int n = matrix[0].length;
- int start = 0;
- int end = m*n-1;
- while(start<=end){
- int mid=(start+end)/2;
- int midX=mid/n;
- int midY=mid%n;
- if(matrix[midX][midY]==target)
- return true;
- if(matrix[midX][midY]<target){
- start=mid+1;
- }else{
- end=mid-1;
- }
- }
- return false;
- }
- }
题目来源:
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has properties:
1) Integers in each row are sorted from left to right. 2) The first integer of each row is greater than the last integer of the previous row.
For example, consider the following matrix:
[
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]
Given target = 3, return true.
- public class Solution {
- public boolean searchMatrix(int[][] matrix, int target) {
- if(matrix==null || matrix.length==0 || matrix[0].length==0)
- return false;
- int m = matrix.length;
- int n = matrix[0].length;
- int start = 0;
- int end = m*n-1;
- while(start<=end){
- int mid=(start+end)/2;
- int midX=mid/n;
- int midY=mid%n;
- if(matrix[midX][midY]==target)
- return true;
- if(matrix[midX][midY]<target){
- start=mid+1;
- }else{
- end=mid-1;
- }
- }
- return false;
- }
- }
23) Distinct Subsequences Total
题目来源:
Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
For example, given the array [−2,1,−3,4,−1,2,1,−5,4]
, the contiguous subarray [4,−1,2,1]
has the largest sum = 6.
- public int maxSubArray(int[] A) {
- int newsum=A[0];
- int max=A[0];
- for(int i=1;i<A.length;i++){
- newsum=Math.max(newsum+A[i],A[i]);
- max= Math.max(max, newsum);
- }
- return max;
- }
25) Remove Duplicates from Sorted Array
题目来源:
Given a sorted array, remove the duplicates in place such that each element appear only once and return the new length. Do not allocate extra space for another array, you must do this in place with constant memory.
For example, given input array A = [1,1,2], your function should return length = 2, and A is now [1,2].
解法:- // Create an array with all unique elements
- public static int[] removeDuplicates(int[] A) {
- if (A.length < 2)
- return A;
- int j = 0;
- int i = 1;
- while (i < A.length) {
- if (A[i] == A[j]) {
- i++;
- } else {
- j++;
- A[j] = A[i];
- i++;
- }
- }
- int[] B = Arrays.copyOf(A, j + 1);
- return B;
- }
- public static void main(String[] args) {
- int[] arr = { 1, 2, 2, 3, 3 };
- arr = removeDuplicates(arr);
- System.out.println(arr.length);
- }
26) Remove Duplicates from Sorted Array II
题目来源:
Follow up for "Remove Duplicates": What if duplicates are allowed at most twice?
For example, given sorted array A = [1,1,1,2,2,3], your function should return length = 5, and A is now [1,1,2,2,3].
解法:- public class Solution {
- public int removeDuplicates(int[] A) {
- if (A.length <= 2)
- return A.length;
- int prev = 1; // point to previous
- int curr = 2; // point to current
- while (curr < A.length) {
- if (A[curr] == A[prev] && A[curr] == A[prev - 1]) {
- curr++;
- } else {
- prev++;
- A[prev] = A[curr];
- curr++;
- }
- }
- return prev + 1;
- }
- }
27) Longest Substring Without Repeating Characters
题目来源:
Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1.
解法1:
The first solution is like the problem of "determine if a string has all unique characters" in CC 150. We can use a flag array to track the existing characters for the longest substring without repeating characters.
- public int lengthOfLongestSubstring(String s) {
- boolean[] flag = new boolean[256];
- int result = 0;
- int start = 0;
- char[] arr = s.toCharArray();
- for (int i = 0; i < arr.length; i++) {
- char current = arr[i];
- if (flag[current]) {
- result = Math.max(result, i - start);
- // the loop update the new start point
- // and reset flag array
- // for example, abccab, when it comes to 2nd c,
- // it update start from 0 to 3, reset flag for a,b
- for (int k = start; k < i; k++) {
- if (arr[k] == current) {
- start = k + 1;
- break;
- }
- flag[arr[k]] = false;
- }
- } else {
- flag[current] = true;
- }
- }
- result = Math.max(arr.length - start, result);
- return result;
- }
解法2:
This solution is from Tia. It is easier to understand than the first solution.
The basic idea is using a hash table to track existing characters and their position. When a repeated character occurs, check from the previously repeated character. However, the time complexity is higher - O(n^3).
- public static int lengthOfLongestSubstring(String s) {
- char[] arr = s.toCharArray();
- int pre = 0;
- HashMap<Character, Integer> map = new HashMap<Character, Integer>();
- for (int i = 0; i < arr.length; i++) {
- if (!map.containsKey(arr[i])) {
- map.put(arr[i], i);
- } else {
- pre = Math.max(pre, map.size());
- i = map.get(arr[i]);
- map.clear();
- }
- }
- return Math.max(pre, map.size());
- }
28) Longest Substring that contains 2 unique characters
题目来源:
This is a problem asked by Google.
Problem
Given a string, find the longest substring that contains only two unique characters. For example, given "abcbbbbcccbdddadacb", the longest substring that contains 2 unique character is "bcbbbbcccb".
解法:
- public static String subString(String s) {
- // checking
- char[] arr = s.toCharArray();
- int max = 0;
- int j = 0;
- int m = 0, n = 0;
- HashSet<Character> set = new HashSet<Character>();
- set.add(arr[0]);
- for (int i = 1; i < arr.length; i++) {
- if (set.add(arr[i])) {
- if (set.size() > 2) {
- String str = s.substring(j, i);
- //keep the last character only
- set.clear();
- set.add(arr[i - 1]);
- if ((i - j) > max) {
- m = j;
- n = i - 1;
- max = i - j;
- }
- j = i - helper(str);
- }
- }
- }
- return s.substring(m, n + 1);
- }
- // This method returns the length that contains only one character from right side.
- public static int helper(String str) {
- // null & illegal checking here
- if(str == null){
- return 0;
- }
- if(str.length() == 1){
- return 1;
- }
- char[] arr = str.toCharArray();
- char p = arr[arr.length - 1];
- int result = 1;
- for (int i = arr.length - 2; i >= 0; i--) {
- if (p == arr[i]) {
- result++;
- } else {
- break;
- }
- }
- return result;
- }
题目来源:
Given an input string, reverse the string word by word.
For example, given s = "the sky is blue", return "blue is sky the".
解:- class Solution {
- public String reverseWords(String s) {
- if (s == null || s.length() == 0) {
- return "";
- }
- // split to words by space
- String[] arr = s.split(" ");
- StringBuilder sb = new StringBuilder();
- for (int i = arr.length - 1; i >= 0; --i) {
- if (!arr[i].equals("")) {
- sb.append(arr[i]).append(" ");
- }
- }
- return sb.length() == 0 ? "" : sb.substring(0, sb.length() - 1);
- }
- }
31) Find Minimum in Rotated Sorted Array
题目来源:
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.
解:- public class Solution {
- public int findPeakElement(int[] num) {
- int max = num[0];
- int index = 0;
- for(int i=1; i<=num.length-2; i++){
- int prev = num[i-1];
- int curr = num[i];
- int next = num[i+1];
- if(curr > prev && curr > next && curr > max){
- index = i;
- max = curr;
- }
- }
- if(num[num.length-1] > max){
- return num.length-1;
- }
- return index;
- }
- }
题目来源:
Problem:
Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.
You may assume that the array is non-empty and the majority element always exist in the array.
We can sort the array first, which takes time of nlog(n). Then scan once to find the longest consecutive substrings.
- public class Solution {
- public int majorityElement(int[] num) {
- if(num.length==1){
- return num[0];
- }
- Arrays.sort(num);
- int prev=num[0];
- int count=1;
- for(int i=1; i<num.length; i++){
- if(num[i] == prev){
- count++;
- if(count > num.length/2) return num[i];
- }else{
- count=1;
- prev = num[i];
- }
- }
- return 0;
- }
- }
解法2:
Thanks to SK. His/her solution is much efficient and simpler.
Since the majority always take more than a half space, the middle element is guaranteed to be the majority. Sorting array takes nlog(n). So the time complexity of this solution is nlog(n). Cheers!
- public int majorityElement(int[] num) {
- if (num.length == 1) {
- return num[0];
- }
- Arrays.sort(num);
- return num[num.length / 2];
- }
题目来源:
Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. The same repeated number may be chosen from C unlimited number of times.
Note:
All numbers (including target) will be positive integers.解法:
Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
The solution set must not contain duplicate combinations.
For example, given candidate set 2,3,6,7 and target 7,
A solution set is:
[7]
[2, 2, 3]
The first impression of this problem should be depth-first search(DFS). To solve DFS problem, recursion is a normal implementation.
Note that the candidates array is not sorted, we need to sort it first.
- public ArrayList<ArrayList<Integer>> combinationSum(int[] candidates, int target) {
- ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
- if(candidates == null || candidates.length == 0) return result;
- ArrayList<Integer> current = new ArrayList<Integer>();
- Arrays.sort(candidates);
- combinationSum(candidates, target, 0, current, result);
- return result;
- }
- public void combinationSum(int[] candidates, int target, int j, ArrayList<Integer> curr, ArrayList<ArrayList<Integer>> result){
- if(target == 0){
- ArrayList<Integer> temp = new ArrayList<Integer>(curr);
- result.add(temp);
- return;
- }
- for(int i=j; i<candidates.length; i++){
- if(target < candidates[i])
- return;
- curr.add(candidates[i]);
- combinationSum(candidates, target - candidates[i], i, curr, result);
- curr.remove(curr.size()-1);
- }
- }
36) Best Time to Buy and Sell Stock
题目来源:
Say you have an array for which the ith element is the price of a given stock on day i.
If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit.
解法1:- public int maxProfit(int[] prices) {
- if(prices == null || prices.length < 2){
- return 0;
- }
- int profit = Integer.MIN_VALUE;
- for(int i=0; i<prices.length-1; i++){
- for(int j=0; j< prices.length; j++){
- if(profit < prices[j] - prices[i]){
- profit = prices[j] - prices[i];
- }
- }
- }
- return profit;
- }
解法2:
- public int maxProfit(int[] prices) {
- int profit = 0;
- int minElement = Integer.MAX_VALUE;
- for(int i=0; i<prices.length; i++){
- profit = Math.max(profit, prices[i]-minElement);
- minElement = Math.min(minElement, prices[i]);
- }
- return profit;
- }
36) 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).
思路:This problem can be viewed as finding all ascending sequences. For example, given {5, 1, 2, 3, 4}, buy at 1 & sell at 4 is the same as buy at 1 &sell at 2 & buy at 2& sell at 3 & buy at 3 & sell at 4.
We can scan the array once, and find all pairs of elements that are in ascending order.
解:- public int maxProfit(int[] prices) {
- int profit = 0;
- for(int i=1; i<prices.length; i++){
- int diff = prices[i]-prices[i-1];
- if(diff > 0){
- profit += diff;
- }
- }
- return profit;
- }
36) Best Time to Buy and Sell Stock III (DP)
2. 链表
在Java中,链表的实现非常简单,每个节点Node都有一个值val和指向下个节点的链接next。
class Node {
int val;
Node next;
Node(int x) {
val = x;
next = null;
}
}
链表两个著名的应用是栈Stack和队列Queue。在Java标准库都都有实现,一个是Stack,另一个是LinkedList(Queue是它实现的接口)。
经典题目:
题目来源:
The problem:
Given a singly linked list L: L0→L1→ ... →Ln-1→Ln,
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→...
For example, given {1,2,3,4}, reorder it to {1,4,2,3}. You must do this in-place without altering the nodes' values.
思路:This problem is not straightforward, because it requires "in-place" operations. That means we can only change their pointers, not creating a new list.
This problem can be solved by doing the following:
- Break list in the middle to two lists (use fast & slow pointers)
- Reverse the order of the second list
- Merge two list back together
- //Class definition of ListNode
- class ListNode {
- int val;
- ListNode next;
- ListNode(int x) {
- val = x;
- next = null;
- }
- }
- public class ReorderList {
- public static void main(String[] args) {
- ListNode n1 = new ListNode(1);
- ListNode n2 = new ListNode(2);
- ListNode n3 = new ListNode(3);
- ListNode n4 = new ListNode(4);
- n1.next = n2;
- n2.next = n3;
- n3.next = n4;
- printList(n1);
- reorderList(n1);
- printList(n1);
- }
- public static void reorderList(ListNode head) {
- if (head != null && head.next != null) {
- ListNode slow = head;
- ListNode fast = head;
- //use a fast and slow pointer to break the link to two parts.
- while (fast != null && fast.next != null && fast.next.next!= null) {
- //why need third/second condition?
- System.out.println("pre "+slow.val + " " + fast.val);
- slow = slow.next;
- fast = fast.next.next;
- System.out.println("after " + slow.val + " " + fast.val);
- }
- ListNode second = slow.next;
- slow.next = null;// need to close first part
- // now should have two lists: head and fast
- // reverse order for second part
- second = reverseOrder(second);
- ListNode p1 = head;
- ListNode p2 = second;
- //merge two lists here
- while (p2 != null) {
- ListNode temp1 = p1.next;
- ListNode temp2 = p2.next;
- p1.next = p2;
- p2.next = temp1;
- p1 = temp1;
- p2 = temp2;
- }
- }
- }
- public static ListNode reverseOrder(ListNode head) {
- if (head == null || head.next == null) {
- return head;
- }
- ListNode pre = head;
- ListNode curr = head.next;
- while (curr != null) {
- ListNode temp = curr.next;
- curr.next = pre;
- pre = curr;
- curr = temp;
- }
- // set head node's next
- head.next = null;
- return pre;
- }
- public static void printList(ListNode n) {
- System.out.println("------");
- while (n != null) {
- System.out.print(n.val);
- n = n.next;
- }
- System.out.println();
- }
- }
题目来源:Given a linked list, determine if it has a cycle in it.
解:
The problem can be demonstrated in the following diagram:
Use fast and low pointer. The advantage about fast/slow pointers is that when a circle is located, the fast one will catch the slow one for sure.
- public class Solution {
- public boolean hasCycle(ListNode head) {
- ListNode fast = head;
- ListNode slow = head;
- if(head == null)
- return false;
- if(head.next == null)
- return false;
- while(fast != null && fast.next != null){
- slow = slow.next;
- fast = fast.next.next;
- if(slow == fast)
- return true;
- }
- return false;
- }
- }
4) Copy List with Random Pointer
题目来源:
Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.
解:
Key to solve this problem
The key to solve the problem is defining a fake head. Then compare the first elements from each list. Add the smaller one to the merged list. Finally, when one of them is empty, simply append it to the merged list, since it is already sorted.
- /**
- * Definition for singly-linked list.
- * public class ListNode {
- * int val;
- * ListNode next;
- * ListNode(int x) {
- * val = x;
- * next = null;
- * }
- * }
- */
- public class Solution {
- public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
- ListNode p1 = l1;
- ListNode p2 = l2;
- ListNode fakeHead = new ListNode(0);
- ListNode p = fakeHead;
- while(p1 != null && p2 != null){
- if(p1.val <= p2.val){
- p.next = p1;
- p1 = p1.next;
- }else{
- p.next = p2;
- p2 = p2.next;
- }
- p = p.next;
- }
- if(p1 != null)
- p.next = p1;
- if(p2 != null)
- p.next = p2;
- return fakeHead.next;
- }
- }
题目来源:
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
解:
The simplest solution is using PriorityQueue. The elements of the priority queue are ordered according to their natural ordering, or by a comparator provided at the construction time (in this case).
- import java.util.ArrayList;
- import java.util.Comparator;
- import java.util.PriorityQueue;
- // Definition for singly-linked list.
- class ListNode {
- int val;
- ListNode next;
- ListNode(int x) {
- val = x;
- next = null;
- }
- }
- public class Solution {
- public ListNode mergeKLists(ArrayList<ListNode> lists) {
- if (lists.size() == 0)
- return null;
- //PriorityQueue is a sorted queue
- PriorityQueue<ListNode> q = new PriorityQueue<ListNode>(lists.size(),
- new Comparator<ListNode>() {
- public int compare(ListNode a, ListNode b) {
- if (a.val > b.val)
- return 1;
- else if(a.val == b.val)
- return 0;
- else
- return -1;
- }
- });
- //add first node of each list to the queue
- for (ListNode list : lists) {
- if (list != null)
- q.add(list);
- }
- ListNode head = new ListNode(0);
- ListNode p = head; // serve as a pointer/cursor
- while (q.size() > 0) {
- ListNode temp = q.poll();
- //poll() retrieves and removes the head of the queue - q.
- p.next = temp;
- //keep adding next element of each list
- if (temp.next != null)
- q.add(temp.next);
- p = p.next;
- }
- return head.next;
- }
- }
7) Remove Duplicates from Sorted List
题目来源:
Given a sorted linked list, delete all duplicates such that each element appear only once.
For example,
Given 1->1->2, return 1->2.解法1:
Given 1->1->2->3->3, return 1->2->3.
- /**
- * Definition for singly-linked list.
- * public class ListNode {
- * int val;
- * ListNode next;
- * ListNode(int x) {
- * val = x;
- * next = null;
- * }
- * }
- */
- public class Solution {
- public ListNode deleteDuplicates(ListNode head) {
- if(head == null || head.next == null)
- return head;
- ListNode prev = head;
- ListNode p = head.next;
- while(p != null){
- if(p.val == prev.val){
- prev.next = p.next;
- p = p.next;
- //no change prev
- }else{
- prev = p;
- p = p.next;
- }
- }
- return head;
- }
- }
解法2:
- public class Solution {
- public ListNode deleteDuplicates(ListNode head) {
- if(head == null || head.next == null)
- return head;
- ListNode p = head;
- while( p!= null && p.next != null){
- if(p.val == p.next.val){
- p.next = p.next.next;
- }else{
- p = p.next;
- }
- }
- return head;
- }
- }
题目来源:
Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.
You should preserve the original relative order of the nodes in each of the two partitions.
For example,
Given 1->4->3->2->5->2 and x = 3,
return 1->2->2->4->3->5.
- public class Solution {
- public ListNode partition(ListNode head, int x) {
- if(head == null) return null;
- ListNode fakeHead1 = new ListNode(0);
- ListNode fakeHead2 = new ListNode(0);
- fakeHead1.next = head;
- ListNode p = head;
- ListNode prev = fakeHead1;
- ListNode p2 = fakeHead2;
- while(p != null){
- if(p.val < x){
- p = p.next;
- prev = prev.next;
- }else{
- p2.next = p;
- prev.next = p.next;
- p = prev.next;
- p2 = p2.next;
- }
- }
- // close the list
- p2.next = null;
- prev.next = fakeHead2.next;
- return fakeHead1.next;
- }
- }
3. 树
这里的树通常是指二叉树,每个节点都包含一个左孩子节点和右孩子节点,像下面这样:
class TreeNode{
int value;
TreeNode left;
TreeNode right;
}
下面是与树相关的一些概念:
二叉搜索树:左结点 <= 中结点 <= 右结点
平衡 vs. 非平衡:平衡二叉树中,每个节点的左右子树的深度相差至多为1(1或0)。
满二叉树(Full Binary Tree):除叶子节点以为的每个节点都有两个孩子。
完美二叉树(Perfect Binary Tree):是具有下列性质的满二叉树:所有的叶子节点都有相同的深度或处在同一层次,且每个父节点都必须有两个孩子。
完全二叉树(Complete Binary Tree):二叉树中,可能除了最后一个,每一层都被完全填满,且所有节点都必须尽可能想左靠。
经典题目:
1) Binary Tree Preorder Traversal
题目来源:
Preorder binary tree traversal is a classic interview problem about trees. The key to solve this problem is to understand the following:
- What is preorder? (parent node is processed before its children)
- Use Stack from Java Core library
It is not obvious what preorder for some strange cases. However, if you draw a stack and manually execute the program, how each element is pushed and popped is obvious.
The key to solve this problem is using a stack to store left and right children, and push right child first so that it is processed after the left child.
解:- public class TreeNode {
- int val;
- TreeNode left;
- TreeNode right;
- TreeNode(int x) { val = x; }
- }
- public class Solution {
- public ArrayList<Integer> preorderTraversal(TreeNode root) {
- ArrayList<Integer> returnList = new ArrayList<Integer>();
- if(root == null)
- return returnList;
- Stack<TreeNode> stack = new Stack<TreeNode>();
- stack.push(root);
- while(!stack.empty()){
- TreeNode n = stack.pop();
- returnList.add(n.val);
- if(n.right != null){
- stack.push(n.right);
- }
- if(n.left != null){
- stack.push(n.left);
- }
- }
- return returnList;
- }
- }
2) Binary Tree Inorder Traversal
题目来源:
The key to solve inorder traversal of binary tree includes the following:
- The order of "inorder" is: left child -> parent -> right child
- Use a stack to track nodes
- Understand when to push node into the stack and when to pop node out of the stack
- public class TreeNode {
- int val;
- TreeNode left;
- TreeNode right;
- TreeNode(int x) { val = x; }
- }
- public class Solution {
- public ArrayList<Integer> inorderTraversal(TreeNode root) {
- // IMPORTANT: Please reset any member data you declared, as
- // the same Solution instance will be reused for each test case.
- ArrayList<Integer> lst = new ArrayList<Integer>();
- if(root == null)
- return lst;
- Stack<TreeNode> stack = new Stack<TreeNode>();
- //define a pointer to track nodes
- TreeNode p = root;
- while(!stack.empty() || p != null){
- // if it is not null, push to stack
- //and go down the tree to left
- if(p != null){
- stack.push(p);
- p = p.left;
- // if no left child
- // pop stack, process the node
- // then let p point to the right
- }else{
- TreeNode t = stack.pop();
- lst.add(t.val);
- p = t.right;
- }
- }
- return lst;
- }
- }
3) Binary Tree Postorder Traversal
题目来源:
The key to to iterative postorder traversal is the following:
- The order of "Postorder" is: left child -> right child -> parent node.
- Find the relation between the previously visited node and the current node
- Use a stack to track nodes
As we go down the tree, check the previously visited node. If it is the parent of the current node, we should add current node to stack. When there is no children for current node, pop it from stack. Then the previous node become to be under the current node for next loop.
解:- public class TreeNode {
- int val;
- TreeNode left;
- TreeNode right;
- TreeNode(int x) { val = x; }
- }
- public class Solution {
- public ArrayList<Integer> postorderTraversal(TreeNode root) {
- ArrayList<Integer> lst = new ArrayList<Integer>();
- if(root == null)
- return lst;
- Stack<TreeNode> stack = new Stack<TreeNode>();
- stack.push(root);
- TreeNode prev = null;
- while(!stack.empty()){
- TreeNode curr = stack.peek();
- // go down the tree.
- //check if current node is leaf, if so, process it and pop stack,
- //otherwise, keep going down
- if(prev == null || prev.left == curr || prev.right == curr){
- //prev == null is the situation for the root node
- if(curr.left != null){
- stack.push(curr.left);
- }else if(curr.right != null){
- stack.push(curr.right);
- }else{
- stack.pop();
- lst.add(curr.val);
- }
- //go up the tree from left node
- //need to check if there is a right child
- //if yes, push it to stack
- //otherwise, process parent and pop stack
- }else if(curr.left == prev){
- if(curr.right != null){
- stack.push(curr.right);
- }else{
- stack.pop();
- lst.add(curr.val);
- }
- //go up the tree from right node
- //after coming back from right node, process parent node and pop stack.
- }else if(curr.right == prev){
- stack.pop();
- lst.add(curr.val);
- }
- prev = curr;
- }
- return lst;
- }
- }
题目来源:
The problem:
Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that:
Only one letter can be changed at a time
Each intermediate word must exist in the dictionary
For example,
Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]
As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog", the program should return its length 5.
Note:
Return 0 if there is no such transformation sequence.
All words have the same length.
All words contain only lowercase alphabetic characters.
This problem is a classic problem that has been asked frequently during interviews. The following are two Java solutions.
解:So we quickly realize that this looks like a tree searching problem for which breath first guarantees the optimal solution.
Assuming we have some words in the dictionary, and the start is "hit" as shown in the diagram below.
- public int ladderLength(String start, String end, HashSet<String> dict) {
- if (dict.size() == 0)
- return 0;
- dict.add(end);
- LinkedList<String> wordQueue = new LinkedList<String>();
- LinkedList<Integer> distanceQueue = new LinkedList<Integer>();
- wordQueue.add(start);
- distanceQueue.add(1);
- //track the shortest path
- int result = Integer.MAX_VALUE;
- while (!wordQueue.isEmpty()) {
- String currWord = wordQueue.pop();
- Integer currDistance = distanceQueue.pop();
- if (currWord.equals(end)) {
- result = Math.min(result, currDistance);
- }
- for (int i = 0; i < currWord.length(); i++) {
- char[] currCharArr = currWord.toCharArray();
- for (char c = 'a'; c <= 'z'; c++) {
- currCharArr[i] = c;
- String newWord = new String(currCharArr);
- if (dict.contains(newWord)) {
- wordQueue.add(newWord);
- distanceQueue.add(currDistance + 1);
- dict.remove(newWord);
- }
- }
- }
- }
- if (result < Integer.MAX_VALUE)
- return result;
- else
- return 0;
- }
5) Validate Binary Search Tree
题目来源:
Given a binary tree, determine if it is a valid binary search tree (BST).
解:
All values on the left sub tree must be less than root, and all values on the right sub tree must be greater than root.
- // Definition for binary tree
- class TreeNode {
- int val;
- TreeNode left;
- TreeNode right;
- TreeNode(int x) {
- val = x;
- }
- }
- public class Solution {
- public static boolean isValidBST(TreeNode root) {
- return validate(root, Integer.MIN_VALUE, Integer.MAX_VALUE);
- }
- public static boolean validate(TreeNode root, int min, int max) {
- if (root == null) {
- return true;
- }
- // not in range
- if (root.val <= min || root.val >= max) {
- return false;
- }
- // left subtree must be < root.val && right subtree must be > root.val
- return validate(root.left, min, root.val) && validate(root.right, root.val, max);
- }
- }
6) Flatten Binary Tree to Linked List
题目来源:
Given a binary tree, flatten it to a linked list in-place.
For example,
Given
1
/ \
2 5
/ \ \
3 4 6
The flattened tree should look like:
1解:
\
2
\
3
\
4
\
5
\
6
Go down through the left, when right is not null, push right to stack.
- /**
- * Definition for binary tree
- * public class TreeNode {
- * int val;
- * TreeNode left;
- * TreeNode right;
- * TreeNode(int x) { val = x; }
- * }
- */
- public class Solution {
- public void flatten(TreeNode root) {
- Stack<TreeNode> stack = new Stack<TreeNode>();
- TreeNode p = root;
- while(p != null || !stack.empty()){
- if(p.right != null){
- stack.push(p.right);
- }
- if(p.left != null){
- p.right = p.left;
- p.left = null;
- }else if(!stack.empty()){
- TreeNode temp = stack.pop();
- p.right=temp;
- }
- p = p.right;
- }
- }
- }
题目来源:
Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.
For example:
Given the below binary tree and sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.
解法1:Add all node to a queue and store sum value of each node to another queue. When it is a leaf node, check the stored sum value.
For the tree above, the queue would be: 5 - 4 - 8 - 11 - 13 - 4 - 7 - 2 - 1. It will check node 13, 7, 2 and 1. This is a typical breadth first search(BFS) problem.
- /**
- * Definition for binary tree
- * public class TreeNode {
- * int val;
- * TreeNode left;
- * TreeNode right;
- * TreeNode(int x) { val = x; }
- * }
- */
- public class Solution {
- public boolean hasPathSum(TreeNode root, int sum) {
- if(root == null) return false;
- LinkedList<TreeNode> nodes = new LinkedList<TreeNode>();
- LinkedList<Integer> values = new LinkedList<Integer>();
- nodes.add(root);
- values.add(root.val);
- while(!nodes.isEmpty()){
- TreeNode curr = nodes.poll();
- int sumValue = values.poll();
- if(curr.left == null && curr.right == null && sumValue==sum){
- return true;
- }
- if(curr.left != null){
- nodes.add(curr.left);
- values.add(sumValue+curr.left.val);
- }
- if(curr.right != null){
- nodes.add(curr.right);
- values.add(sumValue+curr.right.val);
- }
- }
- return false;
- }
- }
解法2:
Java Solution 2 - Recursion
- public boolean hasPathSum(TreeNode root, int sum) {
- if (root == null)
- return false;
- if (root.val == sum && (root.left == null && root.right == null))
- return true;
- return hasPathSum(root.left, sum - root.val)
- || hasPathSum(root.right, sum - root.val);
- }
8) Construct Binary Tree from Inorder and Postorder Traversal
题目来源:
Given inorder and postorder traversal of a tree, construct the binary tree.
Throughts
This problem can be illustrated by using a simple example.
in-order: 4 2 5 (1) 6 7 3 8
post-order: 4 5 2 6 7 8 3 (1)
From the post-order array, we know that last element is the root. We can find the root in in-order array. Then we can identify the left and right sub-trees of the root from in-order array.
Using the length of left sub-tree, we can identify left and right sub-trees in post-order array. Recursively, we can build up the tree.
解:- //Definition for binary tree
- public class TreeNode {
- int val;
- TreeNode left;
- TreeNode right;
- TreeNode(int x) { val = x; }
- }
- public class Solution {
- public TreeNode buildTree(int[] inorder, int[] postorder) {
- int inStart = 0;
- int inEnd = inorder.length-1;
- int postStart =0;
- int postEnd = postorder.length-1;
- return buildTree(inorder, inStart, inEnd, postorder, postStart, postEnd);
- }
- public TreeNode buildTree(int[] inorder, int inStart, int inEnd,
- int[] postorder, int postStart, int postEnd){
- if(inStart > inEnd || postStart > postEnd)
- return null;
- int rootValue = postorder[postEnd];
- TreeNode root = new TreeNode(rootValue);
- int k=0;
- for(int i=0; i< inorder.length; i++){
- if(inorder[i]==rootValue){
- k = i;
- break;
- }
- }
- root.left = buildTree(inorder, inStart, k-1, postorder, postStart, postStart+k-(inStart+1));
- // Becuase k is not the length, it it need to -(inStart+1) to get the length
- root.right = buildTree(inorder, k+1, inEnd, postorder, postStart+k-inStart, postEnd-1);
- // postStart+k-inStart = postStart+k-(inStart+1) +1
- return root;
- }
- }
9) Convert Sorted Array to Binary Search Tree
题目来源:
Given an array where elements are sorted in ascending order, convert it to a height balanced BST.
解:
- // Definition for binary tree
- class TreeNode {
- int val;
- TreeNode left;
- TreeNode right;
- TreeNode(int x) {
- val = x;
- }
- }
- public class Solution {
- public TreeNode sortedArrayToBST(int[] num) {
- if (num.length == 0)
- return null;
- return sortedArrayToBST(num, 0, num.length - 1);
- }
- public TreeNode sortedArrayToBST(int[] num, int start, int end) {
- if (start > end)
- return null;
- int mid = (start + end) / 2;
- TreeNode root = new TreeNode(num[mid]);
- root.left = sortedArrayToBST(num, start, mid - 1);
- root.right = sortedArrayToBST(num, mid + 1, end);
- return root;
- }
- }
10) Convert Sorted List to Binary Search Tree
11) Minimum Depth of Binary Tree
题目来源:
Given a binary tree, find its minimum depth.
The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
解:Need to know LinkedList is a queue. add() and remove() are the two methods to manipulate the queue.
- /**
- * Definition for binary tree
- * public class TreeNode {
- * int val;
- * TreeNode left;
- * TreeNode right;
- * TreeNode(int x) { val = x; }
- * }
- */
- public class Solution {
- public int minDepth(TreeNode root) {
- if(root == null){
- return 0;
- }
- LinkedList<TreeNode> nodes = new LinkedList<TreeNode>();
- LinkedList<Integer> counts = new LinkedList<Integer>();
- nodes.add(root);
- counts.add(1);
- while(!nodes.isEmpty()){
- TreeNode curr = nodes.remove();
- int count = counts.remove();
- if(curr.left != null){
- nodes.add(curr.left);
- counts.add(count+1);
- }
- if(curr.right != null){
- nodes.add(curr.right);
- counts.add(count+1);
- }
- if(curr.left == null && curr.right == null){
- return count;
- }
- }
- return 0;
- }
- }
12) Binary Tree Maximum Path Sum *
题目来源:
Given a binary tree, find the maximum path sum.
The path may start and end at any node in the tree.
For example:
Given the below binary tree,
1
/ \
2 3
Return 6.
解:1) Recursively solve this problem
2) Get largest left sum and right sum
2) Compare to the stored maximum
- // Definition for binary tree
- class TreeNode {
- int val;
- TreeNode left;
- TreeNode right;
- TreeNode(int x) {
- val = x;
- }
- }
- public class Solution {
- //store max value
- int max;
- public int maxPathSum(TreeNode root) {
- max = (root == null) ? 0 : root.val;
- findMax(root);
- return max;
- }
- public int findMax(TreeNode node) {
- if (node == null)
- return 0;
- // recursively get sum of left and right path
- int left = Math.max(findMax(node.left), 0);
- int right = Math.max(findMax(node.right), 0);
- //update maximum here
- max = Math.max(node.val + left + right, max);
- // return sum of largest path of current node
- return node.val + Math.max(left, right);
- }
- }
题目来源:
Given a binary tree, determine if it is height-balanced.
For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.
解:
- // Definition for binary tree
- class TreeNode {
- int val;
- TreeNode left;
- TreeNode right;
- TreeNode(int x) {
- val = x;
- }
- }
- public class Solution {
- public boolean isBalanced(TreeNode root) {
- if (root == null)
- return true;
- if (getHeight(root) == -1)
- return false;
- return true;
- }
- public int getHeight(TreeNode root) {
- if (root == null)
- return 0;
- int left = getHeight(root.left);
- int right = getHeight(root.right);
- if (left == -1 || right == -1)
- return -1;
- if (Math.abs(left - right) > 1) {
- return -1;
- }
- return Math.max(left, right) + 1;
- }
- }
4. 图
图相关的问题主要集中在深度优先搜索(depth first search)和广度优先搜索(breath first search)。深度优先搜索很简单,广度优先要注意使用queue. 下面是一个简单的用队列Queue实现广度优先搜索。
public class GraphTest {
public static void breathFirstSearch(GraphNode root, int x){
if(root.val == x)
System.out.println("find in root");
Queue queue = new Queue();
root.visited = true;
queue.enqueue(root);
while(queue.first != null){
GraphNode c = (GraphNode) queue.dequeue();
for(GraphNode n: c.neighbors){
if(!n.visited){
System.out.print(n + " ");
n.visited = true;
if(n.val == x)
System.out.println("Find "+n);
queue.enqueue(n);
}
}
}
}
}
经典题目:
题目来源:
Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors.
Key to Solve This Problem
- A queue is used to do breath first traversal.
- a map is used to store the visited nodes. It is the map between original node and copied node.
It would be helpful if you draw a diagram and visualize the problem.
解:- /**
- * Definition for undirected graph.
- * class UndirectedGraphNode {
- * int label;
- * ArrayList<UndirectedGraphNode> neighbors;
- * UndirectedGraphNode(int x) { label = x; neighbors = new ArrayList<UndirectedGraphNode>(); }
- * };
- */
- public class Solution {
- public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
- if(node == null)
- return null;
- LinkedList<UndirectedGraphNode> queue = new LinkedList<UndirectedGraphNode>();
- HashMap<UndirectedGraphNode, UndirectedGraphNode> map =
- new HashMap<UndirectedGraphNode,UndirectedGraphNode>();
- UndirectedGraphNode newHead = new UndirectedGraphNode(node.label);
- queue.add(node);
- map.put(node, newHead);
- while(!queue.isEmpty()){
- UndirectedGraphNode curr = queue.pop();
- ArrayList<UndirectedGraphNode> currNeighbors = curr.neighbors;
- for(UndirectedGraphNode aNeighbor: currNeighbors){
- if(!map.containsKey(aNeighbor)){
- UndirectedGraphNode copy = new UndirectedGraphNode(aNeighbor.label);
- map.put(aNeighbor,copy);
- map.get(curr).neighbors.add(copy);
- queue.add(aNeighbor);
- }else{
- map.get(curr).neighbors.add(map.get(aNeighbor));
- }
- }
- }
- return newHead;
- }
- }
5. 排序
下面是不同排序算法的时间复杂度,你可以去wiki看一下这些算法的基本思想。
Algorithm | Average Time | Worst Time | Space |
冒泡排序(Bubble sort) | n^2 | n^2 | 1 |
选择排序(Selection sort) | n^2 | n^2 | 1 |
插入排序(Insertion sort) | n^2 | n^2 | |
快速排序(Quick sort) | n log(n) | n^2 | |
归并排序(Merge sort) | n log(n) | n log(n) | depends |
* 另外还有BinSort, RadixSort和CountSort 三种比较特殊的排序。
经典题目: Mergesort, Quicksort, InsertionSort.
快速排序:
Quicksort is a divide and conquer algorithm. It first divides a large list into two smaller sub-lists and then recursively sort the two sub-lists. If we want to sort an array without any extra space, Quicksort is a good option. On average, time complexity is O(n log(n)).
The basic step of sorting an array are as follows:
- Select a pivot, normally the middle one
- From both ends, swap elements and make all elements on the left less than the pivot and all elements on the right greater than the pivot
- Recursively sort left part and right part
- package algorithm.sort;
- public class QuickSort {
- public static void main(String[] args) {
- int[] x = { 9, 2, 4, 7, 3, 7, 10 };
- printArray(x);
- int low = 0;
- int high = x.length - 1;
- quickSort(x, low, high);
- printArray(x);
- }
- public static void quickSort(int[] arr, int low, int high) {
- if (arr == null || arr.length == 0)
- return;
- if (low >= high)
- return;
- //pick the pivot
- int middle = low + (high - low) / 2;
- int pivot = arr[middle];
- //make left < pivot and right > pivot
- int i = low, j = high;
- while (i <= j) {
- while (arr[i] < pivot) {
- i++;
- }
- while (arr[j] > pivot) {
- j--;
- }
- if (i <= j) {
- int temp = arr[i];
- arr[i] = arr[j];
- arr[j] = temp;
- i++;
- j--;
- }
- }
- //recursively sort two sub parts
- if (low < j)
- quickSort(arr, low, j);
- if (high > i)
- quickSort(arr, i, high);
- }
- public static void printArray(int[] x) {
- for (int a : x)
- System.out.print(a + " ");
- System.out.println();
- }
- }
6. 递归 vs. 迭代
对程序员来说,递归应该是一个与生俱来的思想(a built-in thought),可以通过一个简单的例子来说明。问题:
有n步台阶,一次只能上1步或2步,共有多少种走法。
步骤1:找到走完前n步台阶和前n-1步台阶之间的关系。为了走完n步台阶,只有两种方法:从n-1步台阶爬1步走到或从n-2步台阶处爬2步走到。如果f(n)是爬到第n步台阶的方法数,那么f(n) = f(n-1) + f(n-2)。步骤2: 确保开始条件是正确的。f(0) = 0;f(1) = 1;
public static int f(int n){
if(n <= 2) return n;
int x = f(n-1) + f(n-2);
return x;
}
递归方法的时间复杂度是指数级,因为有很多冗余的计算:
f(5)f(4) + f(3)f(3) + f(2) + f(2) + f(1)f(2) + f(1) + f(1) + f(0) + f(1) + f(0) + f(1)f(1) + f(0) + f(1) + f(1) + f(0) + f(1) + f(0) + f(1)直接的想法是将递归转换为迭代:
public static int f(int n) {
if (n <= 2){
return n;
}
int first = 1, second = 2;
int third = 0;
for (int i = 3; i <= n; i++) {
third = first + second;
first = second;
second = third;
}
return third;
}
这个例子迭代花费的时间更少,你可能复习一个两者的区别Recursion vs Iteration。
7. 动态规划
动态规划是解决下面这些性质类问题的技术:
- 一个问题可以通过更小子问题的解决方法来解决,或者说问题的最优解包含了其子问题的最优解
- 有些子问题的解可能需要计算多次
- 子问题的解存储在一张表格里,这样每个子问题只用计算一次
- 需要额外的空间以节省时间
public static int[] A = new int[100];
public static int f3(int n) {
if (n <= 2)
A[n]= n;
if(A[n] > 0)
return A[n];
else
A[n] = f3(n-1) + f3(n-2);//store results so only calculate once!
return A[n];
}
经典题目:
2) Longest Palindromic Substring
题目来源:
Finding the longest palindromic substring is a classic problem of coding interview. In this post, I will summarize 3 different solutions for this problem.
动态规划:
Let s be the input string, i and j are two indices of the string.
Define a 2-dimension array "table" and let table[i][j] denote whether substring from i to j is palindrome.
Start condition:
table[i][i] == 1;
table[i][i+1] == 1 => s.charAt(i) == s.charAt(i+1)
Changing condition:
table[i+1][j-1] == 1 && s.charAt(i) == s.charAt(j)
=>
table[i][j] == 1
Time O(n^2) Space O(n^2)
- public static String longestPalindrome2(String s) {
- if (s == null)
- return null;
- if(s.length() <=1)
- return s;
- int maxLen = 0;
- String longestStr = null;
- int length = s.length();
- int[][] table = new int[length][length];
- //every single letter is palindrome
- for (int i = 0; i < length; i++) {
- table[i][i] = 1;
- }
- printTable(table);
- //e.g. bcba
- //two consecutive same letters are palindrome
- for (int i = 0; i <= length - 2; i++) {
- if (s.charAt(i) == s.charAt(i + 1)){
- table[i][i + 1] = 1;
- longestStr = s.substring(i, i + 2);
- }
- }
- printTable(table);
- //condition for calculate whole table
- for (int l = 3; l <= length; l++) {
- for (int i = 0; i <= length-l; i++) {
- int j = i + l - 1;
- if (s.charAt(i) == s.charAt(j)) {
- table[i][j] = table[i + 1][j - 1];
- if (table[i][j] == 1 && l > maxLen)
- longestStr = s.substring(i, j + 1);
- } else {
- table[i][j] = 0;
- }
- printTable(table);
- }
- }
- return longestStr;
- }
- public static void printTable(int[][] x){
- for(int [] y : x){
- for(int z: y){
- System.out.print(z + " ");
- }
- System.out.println();
- }
- System.out.println("------");
- }
Given an input, we can use printTable method to examine the table after each iteration. For example, if input string is "dabcba", the final matrix would be the following:
1 0 0 0 0 0
0 1 0 0 0 1
0 0 1 0 1 0
0 0 0 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1
From the table, we can clear see that the longest string is in cell table[1][5].
题目来源:
Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separated sequence of one or more dictionary words.
For example, given
s = "leetcode",
dict = ["leet", "code"].
Return true because "leetcode" can be segmented as "leet code".
动态规划:The key to solve this problem by using dynamic programming approach:
- Define an array t[] such that t[i]==true => 0-(i-1) can be segmented using dictionary
- Initial state t[0] == true
- public class Solution {
- public boolean wordBreak(String s, Set<String> dict) {
- boolean[] t = new boolean[s.length()+1];
- t[0] = true; //set first to be true, why?
- //Because we need initial state
- for(int i=0; i<s.length(); i++){
- //should continue from match position
- if(!t[i])
- continue;
- for(String a: dict){
- int len = a.length();
- int end = i + len;
- if(end > s.length())
- continue;
- if(t[end]) continue;
- if(s.substring(i, end).equals(a)){
- t[end] = true;
- }
- }
- }
- return t[s.length()];
- }
- }
题目来源:
Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
For example, given the array [−2,1,−3,4,−1,2,1,−5,4]
, the contiguous subarray [4,−1,2,1]
has the largest sum = 6.
- public class Solution {
- public int maxSubArray(int[] A) {
- int max = A[0];
- int[] sum = new int[A.length];
- sum[0] = A[0];
- for (int i = 1; i < A.length; i++) {
- sum[i] = Math.max(A[i], sum[i - 1] + A[i]);
- max = Math.max(max, sum[i]);
- }
- return max;
- }
- }
题目来源:
Given a string s, partition s such that every substring of the partition is a palindrome.
Return all possible palindrome partitioning of s.
For example, given s = "aab",
Return
[动态规划:
["aa","b"],
["a","a","b"]
]
The dynamic programming approach is very similar to the problem of longest palindrome substring.
- public static List<String> palindromePartitioning(String s) {
- List<String> result = new ArrayList<String>();
- if (s == null)
- return result;
- if (s.length() <= 1) {
- result.add(s);
- return result;
- }
- int length = s.length();
- int[][] table = new int[length][length];
- // l is length, i is index of left boundary, j is index of right boundary
- for (int l = 1; l <= length; l++) {
- for (int i = 0; i <= length - l; i++) {
- int j = i + l - 1;
- if (s.charAt(i) == s.charAt(j)) {
- if (l == 1 || l == 2) {
- table[i][j] = 1;
- } else {
- table[i][j] = table[i + 1][j - 1];
- }
- if (table[i][j] == 1) {
- result.add(s.substring(i, j + 1));
- }
- } else {
- table[i][j] = 0;
- }
- }
- }
- return result;
- }
8. 位操作
常用位操作符:
OR (|) | AND (&) | XOR (^) | Left Shift (<<) | Right Shift (>>) | Not (~) |
1|0=1 | 1&0=0 | 1^0=1 | 0010<<2=1000 | 1100>>2=0011 | ~1=0 |
用一个题目来理解这些操作 -
获得给定数字n的第i位:(i从0计数并从右边开始)
public static boolean getBit(int num, int i){
int result = num & (1<<i);
if(result == 0){
return false;
}else{
return true;
}
例如,获得数字10的第2位:
i=1, n=101<<1= 101010&10=1010 is not 0, so return true;
9. 概率问题
解决概率相关的问题通常需要先分析问题,下面是一个这类问题的简单例子:
一个房间里有50个人,那么至少有两个人生日相同的概率是多少?(忽略闰年的事实,也就是一年365天)计算某些事情的概率很多时候都可以转换成先计算其相对面。在这个例子里,我们可以计算所有人生日都互不相同的概率,也就是:365/365 * 364/365 * 363/365 * … * (365-49)/365,这样至少两个人生日相同的概率就是1 – 这个值。
public static double caculateProbability(int n){
double x = 1;
for(int i=0; i<n; i++){
x *= (365.0-i)/365.0;
}
double pro = Math.round((1-x) * 100);
return pro/100;
}
calculateProbability(50) = 0.97
经典题目:桶中取球
10. 排列组合
组合和排列的区别在于次序是否关键。例1:
1、2、3、4、5这5个数字,用java写一个方法,打印出所有不同的排列, 如:51234、41235等。要求:"4"不能在第三位,"3"与"5"不能相连。例2:
5个香蕉,4个梨子,3个苹果。同一种水果都是一样的,这个些水果排列成不同的组合有多少情况?
11. 其他类型的题目
主要是不能归到上面10大类的。需要寻找规律,然后解决问题的。 经典题目: Reverse Integer
转自:http://blog.csdn.net/xiaoranlr/article/details/43963933