Updated on 9/22/2017 如今回头看来,里面很多做法都不是最佳的,有的从复杂度上根本就不是最优解,有的写的太啰嗦,有的则用了一些过于 tricky 的方法。我没有为了这个再更新,就让它们去吧。
LeetCode 上面的题目更新很快,而且题目是越来越不好做了。我把最新的 155 到 226 题目的思考和解答过程放在下面,解法有好有坏,有问题我们可以讨论。老规矩,有一些题目是要买一个特定的电子书才可以在线做题的,我就跳过去了。
Title | Acceptance | Difficulty | |
---|---|---|---|
226 | Invert Binary Tree | 37.6% | Easy |
225 | Implement Stack using Queues | 30.0% | Medium |
224 | Basic Calculator | 16.1% | Medium |
223 | Rectangle Area | 26.0% | Easy |
222 | Count Complete Tree Nodes | 19.8% | Medium |
221 | Maximal Square | 20.6% | Medium |
220 | Contains Duplicate III | 15.0% | Medium |
219 | Contains Duplicate II | 26.2% | Easy |
218 | The Skyline Problem | 17.0% | Hard |
217 | Contains Duplicate | 35.9% | Easy |
216 | Combination Sum III | 27.3% | Medium |
215 | Kth Largest Element in an Array | 27.4% | Medium |
214 | Shortest Palindrome | 16.3% | Hard |
213 | House Robber II | 26.1% | Medium |
212 | Word Search II | 15.0% | Hard |
211 | Add and Search Word – Data structure design | 20.9% | Medium |
210 | Course Schedule II | 19.1% | Medium |
209 | Minimum Size Subarray Sum | 23.1% | Medium |
208 | Implement Trie (Prefix Tree) | 25.0% | Medium |
207 | Course Schedule | 21.2% | Medium |
206 | Reverse Linked List | 32.0% | Easy |
205 | Isomorphic Strings | 24.2% | Easy |
204 | Count Primes | 18.9% | Easy |
203 | Remove Linked List Elements | 26.0% | Easy |
202 | Happy Number | 31.5% | Easy |
201 | Bitwise AND of Numbers Range | 27.2% | Medium |
200 | Number of Islands | 21.9% | Medium |
199 | Binary Tree Right Side View | 26.9% | Medium |
198 | House Robber | 28.8% | Easy |
191 | Number of 1 Bits | 37.3% | Easy |
190 | Reverse Bits | 28.3% | Easy |
189 | Rotate Array | 17.8% | Easy |
188 | Best Time to Buy and Sell Stock IV | 17.0% | Hard |
187 | Repeated DNA Sequences | 19.2% | Medium |
186 | Reverse Words in a String II | 31.1% | Medium |
179 | Largest Number | 15.7% | Medium |
174 | Dungeon Game | 17.5% | Hard |
173 | Binary Search Tree Iterator | 29.2% | Medium |
172 | Factorial Trailing Zeroes | 28.3% | Easy |
171 | Excel Sheet Column Number | 36.6% | Easy |
170 | Two Sum III – Data structure design | 24.7% | Easy |
169 | Majority Element | 34.9% | Easy |
168 | Excel Sheet Column Title | 18.1% | Easy |
167 | Two Sum II – Input array is sorted | 43.3% | Medium |
166 | Fraction to Recurring Decimal | 12.6% | Medium |
165 | Compare Version Numbers | 15.1% | Easy |
164 | Maximum Gap | 24.3% | Hard |
163 | Missing Ranges | 24.0% | Medium |
162 | Find Peak Element | 31.4% | Medium |
161 | One Edit Distance | 24.3% | Medium |
160 | Intersection of Two Linked Lists | 28.5% | Easy |
159 | Longest Substring with At Most Two Distinct Characters | 30.3% | Hard |
158 | Read N Characters Given Read4 II – Call multiple times | 22.2% | Hard |
157 | Read N Characters Given Read4 | 29.9% | Easy |
156 | Binary Tree Upside Down | 34.4% | Medium |
155 | Min Stack | 18.3% | Easy |
Invert Binary Tree
【题目】Invert a binary tree.
代码语言:javascript复制 4
/
2 7
/ /
1 3 6 9
to
代码语言:javascript复制 4
/
7 2
/ /
9 6 3 1
Trivia:
This problem was inspired by this original tweet by Max Howell:
Google: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so fuck off.
【解答】这个段子已经在互联网上广为流传了,实际事情的背景我们不得而知。不过如果真是就根据这样一道题来确定一个人的面试结果的话实在有些鲁莽。
代码语言:javascript复制public class Solution {
public TreeNode invertTree(TreeNode root) {
if (root==null)
return null;
TreeNode left = root.left;
TreeNode right = root.right;
root.left = right;
root.right = left;
if (left!=null)
invertTree(left);
if (right!=null)
invertTree(right);
return root;
}
}
Implement Stack using Queues
【题目】Implement the following operations of a stack using queues.
- push(x) — Push element x onto stack.
- pop() — Removes the element on top of the stack.
- top() — Get the top element.
- empty() — Return whether the stack is empty.
Notes:
- You must use only standard operations of a queue — which means only
push to back
,peek/pop from front
,size
, andis empty
operations are valid. - Depending on your language, queue may not be supported natively. You may simulate a queue by using a list or deque (double-ended queue), as long as you use only standard operations of a queue.
- You may assume that all operations are valid (for example, no pop or top operations will be called on an empty stack).
【解答】基本思路是用两个 Queue,每次出栈都需要在两个队列里面来回倒腾。这题到不了 medium 难度。
代码语言:javascript复制class MyStack {
private Queue<Integer> q1 = new LinkedList<Integer>();
private Queue<Integer> q2 = new LinkedList<Integer>();
// Push element x onto stack.
public void push(int x) {
if (!q1.isEmpty()) {
q1.add(x);
} else {
q2.add(x);
}
}
// Removes the element on top of the stack.
public void pop() {
if (!q1.isEmpty()) {
while(q1.size()>1) {
int val = q1.poll();
q2.add(val);
}
q1.poll();
return;
}
if (!q2.isEmpty()) {
while(q2.size()>1) {
int val = q2.poll();
q1.add(val);
}
q2.poll();
return;
}
}
// Get the top element.
public int top() {
if (!q1.isEmpty()) {
int val = 0;
while(!q1.isEmpty()) {
val = q1.poll();
q2.add(val);
}
return val;
}
if (!q2.isEmpty()) {
int val = 0;
while(!q2.isEmpty()) {
val = q2.poll();
q1.add(val);
}
return val;
}
return 0; // invalid
}
// Return whether the stack is empty.
public boolean empty() {
return q1.isEmpty() && q2.isEmpty();
}
}
Basic Calculator
【题目】Implement a basic calculator to evaluate a simple expression string.
The expression string may contain open (
and closing parentheses )
, the plus
or minus sign -
, non-negative integers and empty spaces .
You may assume that the given expression is always valid.
Some examples:
代码语言:javascript复制"1 1" = 2
" 2-1 2 " = 3
"(1 (4 5 2)-3) (6 8)" = 23
Note: Do not use the eval
built-in library function.
【解答】建立一个类 Result,其中 pos 指向当前操作数在整个字符串中的位置,val 放置操作数的值。然后创建 eval 方法,从左向右遍历字符串,空格就跳过,如果遇到左括号就递归调用 eval,遇到右括号就是程序出口。如果是数字,就继续往下试探,必须把这个数的全部数位取出,转化成实际的数以后再往下走。
代码语言:javascript复制class Result {
public int pos;
public int val;
public Result(int pos, int val) {
this.pos = pos;
this.val = val;
}
}
public class Solution {
public int calculate(String s) {
return eval(s, 0).val;
}
private Result eval(String s, int i) {
Integer total = null;
char op = 0;
while (i<s.length()) {
char ch = s.charAt(i);
if (ch==' ') {
i ;
continue;
}
if (ch=='(') {
Result result = eval(s, i 1);
i = result.pos;
if (total==null)
total = result.val;
else
total = cal(op, total, result.val);
} else if (ch==')') {
return new Result(i 1, total);
} else if (ch==' ' || ch=='-') {
op = ch;
i ;
} else {
int start = i;
i ;
while (i!=s.length() && s.charAt(i)>='0' && s.charAt(i)<='9')
i ;
int val = Integer.parseInt(s.substring(start, i).replaceAll(" ", ""));
if (total==null)
total = val;
else
total = cal(op, total, val);
}
}
return new Result(s.length(), total);
}
private int cal(char op, int total, int val) {
if (op==' ')
return total val;
else
return total - val;
}
}
Rectangle Area
【题目】Find the total area covered by two rectilinear rectangles in a 2D plane.
Each rectangle is defined by its bottom left corner and top right corner as shown in the figure.
Assume that the total area is never beyond the maximum possible value of int.
【解答】这个题目主要需要注意的是几种矩形放置情况,考虑二者位置之间的关系。先计算两个矩形的面积之和,考虑到计算过程中的溢出可能,使用 long 存储中间结果。如果没有重叠,直接返回;如果有重叠,那么给所有 x 轴坐标排序,也给 y 坐标排序,两个序列各自中间的两个数构成了重叠部分的面积,减掉即可。
代码语言:javascript复制public class Solution {
public int computeArea(int A, int B, int C, int D, int E, int F, int G, int H) {
// beware of overflow
long total = Math.abs((long)((D-B)*(C-A))) Math.abs((long)((G-E)*(H-F)));
// no overlap
if (
(A<E && A<G && C<E && C<G)
||
(A>E && A>G && C>E && C>G)
||
(B<F && B<H && D<F && D<H)
||
(B>F && B>H && D>F && D>H)
)
return (int)total;
int[] xs = new int[]{A, C, E, G};
int[] ys = new int[]{B, D, F, H};
Arrays.sort(xs);
Arrays.sort(ys);
int overlap = Math.abs((xs[1]-xs[2]) * (ys[1]-ys[2]));
return (int)(total-overlap);
}
}
Count Complete Tree Nodes
【题目】Given a complete binary tree, count the number of nodes.
Definition of a complete binary tree from Wikipedia:
In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.
【解答】要数完全二叉树的节点数,那么如果直接计算,不利用这棵二叉树 “完全” 的特点,是会超时的:
代码语言:javascript复制public class Solution {
public int countNodes(TreeNode root) {
if (root==null)
return 0;
List<TreeNode> list = new ArrayList<>();
list.add(root);
return count(list);
}
private int count(List<TreeNode> list) {
List<TreeNode> newList = new ArrayList<>();
int count = 0;
for (TreeNode node : list) {
count ;
if (node.left!=null)
newList.add(node.left);
if (node.right!=null)
newList.add(node.right);
}
if (newList.isEmpty())
return count;
else
return count count(newList);
}
}
接着观察完全二叉树的特点,假设高度为 h(计数从 1 开始),除去最后一层,每一层都是满节点,且第 x 层的元素个数为 2 的 (x-1) 次方;而到第 x 层为止的满二叉树的总结点数为 2 的 x 次方。
因此最直观的思维是,对于任意 h 高度的完全二叉树,先计算 h-1 部分层数的二叉树的节点总数量,在来单独计算最后一层的数量,这样就需要找到最后一层最末一个元素的位置。但是按照这个思路来看,要寻找这个元素的位置,似乎并不是很好办。
于是换个思路,
判断从根节点每次都取左孩子,一路到底得到的左边沿高度为 left,从根节点每次都取右孩子,一路到底得到的右边沿高度为 right,如果 left==right,那么显然当前所求是满二叉树,应用上面的公式可得;
如果当前不是,那我至少可以在左子树和右子树里继续递归判断是否是满二叉树,一个显而易见的结论是,这个左子树和右子树两个中至少存在一个满二叉树,这样这个满二叉树就可以公式求解(一刀干掉一半),剩下的这个不满的二叉树继续递归求解,这样的复杂度就是 log n 级别。
代码语言:javascript复制public class Solution {
public int countNodes(TreeNode root) {
if (root==null)
return 0;
int left = 1;
TreeNode node = root;
while (node.left!=null) {
node = node.left;
left ;
}
int right = 1;
node = root;
while (node.right!=null) {
node = node.right;
right ;
}
if (left==right)
return (int)(Math.pow(2, left))-1;
else
return 1 countNodes(root.left) countNodes(root.right);
}
}
Maximal Square
【题目】Given a 2D binary matrix filled with 0’s and 1’s, find the largest square containing all 1’s and return its area.
For example, given the following matrix:
代码语言:javascript复制1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
Return 4.
【解答】要找一个全部为 1 的最大矩形。大致思路是,从上往下逐行分析,用一个数组 row 存放累加结果,如果当前数 x 为 0,那么 rowx 为 0,否则为上一行这个位置的结果 1,即累加和。比如题中的例子,
- 截止第一行的累加和是:1,0,1,0,0
- 截止第二行的累加和是:2,0,2,1,1
- 截止第三行的累加和是:3,1,3,2,2
- 截止第四行的累加和是:4,0,0,3,0
这样每构造完一行的累加数组,就可以遍历这一行内的区间 i,j,寻找区间跨度 j-i 1 的最大值,并且满足 rowx, x∈i,j 中所有的 x≥j-i 1。
代码语言:javascript复制public class Solution {
public int maximalSquare(char[][] matrix) {
if (null==matrix || matrix.length==0 || matrix[0].length==0)
return 0;
int max = 0;
int[] row = new int[matrix[0].length];
for (int i=0; i<matrix.length; i ) {
for (int j=0; j<matrix[0].length; j ) {
if (matrix[i][j]=='0')
row[j] = 0;
else
row[j] = 1;
}
int val = maxInRow(row);
if (val>max)
max = val;
}
return max;
}
private int maxInRow(int[] row) {
int max = 0;
for (int i=0; i<row.length; i ) {
int minH = row[i];
for (int j=i; j<row.length; j ) {
if (row[j]==0)
break;
if (row[j]<minH)
minH = row[j];
int len = Math.min(minH, (j-i 1));
int area = len * len;
if (area>max)
max = area;
}
}
return max;
}
}
Contains Duplicate III
【题目】Given an array of integers, find out whether there are two distinct indices i and j in the array such that the difference between numsi and numsj is at most t and the difference between i and j is at most k.
【解答】终于有一道红黑树的题目了。首先在脑海里整理题意,相当于有一个窗口,窗口大小不得超过 k,在窗口移动的过程中,寻找窗口内部元素不超过 t 的情况。
用一个 TreeSet 来存放窗口内的元素们,每来一个新元素,就:
- 使用 floor 方法去找是否已存在小于等于新元素的元素,如果找到,就加上 t 看看是否能够等于或超过新元素,如果是,就说明这两个元素差值小于等于 t;
- 使用 ceiling 方法去找是否已存在大于等于新元素的元素,如果找到,就减掉 t 看看是否能够等于或者小于新元素,如果是,也说明这两个元素差值小于等于 t。
public class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
if (k <= 0 || t < 0)
return false;
TreeSet<Integer> set = new TreeSet<>();
for (int i = 0; i < nums.length; i ) {
int val = nums[i];
if (set.floor(val) != null && val <= t set.floor(val))
return true;
if (set.ceiling(val) != null && set.ceiling(val) <= t val)
return true;
set.add(val);
if (i >= k)
set.remove(nums[i - k]);
}
return false;
}
}
Contains Duplicate II
【题目】Given an array of integers and an integer k, find out whether there there are two distinct indices i and j in the array such that numsi = numsj and the difference between i_and _j is at most k.
【解答】首先要理解题意,其实就是在一个长长的数组中,有一个大小可伸缩的滑动窗口,但是这个窗口的宽度不得超过 j-i 1,在滑动这个窗口的过程中,如果发现两个数相等,那就返回 true。因此使用一个 map 来存放滑动期间收集到的信息,key 是该数,value 是该数最后一次出现的位置。如果某次迭代发现该数再次出现,且两次出现的间距符合要求,就返回。
代码语言:javascript复制public class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
if (null==nums || nums.length<=1 || k<=0)
return false;
Map<Integer, Integer> map = new HashMap<>();
for (int i=0; i<nums.length; i ) {
int num = nums[i];
if (!map.containsKey(num)) {
map.put(num, i);
} else {
int diff = i - map.get(num);
if (diff<=k)
return true;
else
map.put(num, i);
}
}
return false;
}
}
The Skyline Problem
【题目】A city’s skyline is the outer contour of the silhouette formed by all the buildings in that city when viewed from a distance. Now suppose you are given the locations and height of all the buildings as shown on a cityscape photo (Figure A), write a program to output the skyline formed by these buildings collectively (Figure B).
The geometric information of each building is represented by a triplet of integers [Li, Ri, Hi]
, where Li
and Ri
are the x coordinates of the left and right edge of the ith building, respectively, and Hi
is its height. It is guaranteed that 0 ≤ Li, Ri ≤ INT_MAX
, 0 < Hi ≤ INT_MAX
, and Ri - Li > 0
. You may assume all buildings are perfect rectangles grounded on an absolutely flat surface at height 0.
For instance, the dimensions of all buildings in Figure A are recorded as: [ [2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8] ]
.
The output is a list of “key points” (red dots in Figure B) in the format of [ [x1,y1], [x2, y2], [x3, y3], ... ]
that uniquely defines a skyline. A key point is the left endpoint of a horizontal line segment. Note that the last key point, where the rightmost building ends, is merely used to mark the termination of the skyline, and always has zero height. Also, the ground in between any two adjacent buildings should be considered part of the skyline contour.
For instance, the skyline in Figure B should be represented as:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ]
.
Notes:
- The number of buildings in any input list is guaranteed to be in the range
[0, 10000]
. - The input list is already sorted in ascending order by the left x position
Li
. - The output list must be sorted by the x position.
- There must be no consecutive horizontal lines of equal height in the output skyline. For instance,
[...[2 3], [4 5], [7 5], [11 5], [12 7]...]
is not acceptable; the three lines of height 5 should be merged into one in the final output as such:[...[2 3], [4 5], [12 7], ...]
【解答】这道题简直是 LeetCode 里面最难的一道了吧。一开始我的思路是用红黑树(在 Java 里面则是 TreeMap),key 是点的横坐标,value 是高度,扫描一遍数组就可以,但是这种做法遇到的 case 极其多极其绕,做起来非常难受。网上有多种不同方法的解答,有 DP 等等。下面这个方法也是红黑树,但是 key 是高度,value 是同样为止的各种楼的数目。最巧妙的地方有两点,一是排序的标准,二是 TreeMap 的使用。
首先创建分界点 Node,x、y 分别是横纵坐标,start 变量表示是楼房的开始还是结束边界。
接着排序,优先比较 x 的位置,其次比较是否二者都是开始边界或都是结束边界,最后根据开始或者结束的情况来比较 y。在排序以后,这些分界点就满足了这样的顺序:
- 横坐标从小到大;
- 横坐标相同时,楼房左边沿在前,右边沿在后;
- 边沿情况也相同时,如果都为左边沿,高度低的在前,如果都为右边沿,高度高的在前。
这样就保证了从左往右遍历的过程中,高度高的大楼可以覆盖掉高度低的大楼,从而形成合理的天际线。
最后说整个 node list 的遍历,x、y 变量记录下最近一次访问的位置和高度,
- 如果是大楼左边沿,map 相应 entry 的值 1,并且如果出现了不曾有的新高度,更新到最新位置和高度;
- 如果是大楼右边沿,map 相应 entry 的值-1,之后如果 map 为空,说明到地面了;如果不为空,找 map 中最高大楼的 entry(TreeMap 的作用就体现在这里,entry 有序),更新 y 为最高大楼的高度(矮楼要被高楼覆盖),而 x 使用当前位置。
public class Solution {
class Node {
boolean start;
int x;
int y;
public Node(int x, int y, boolean start) {
this.x = x;
this.y = y;
this.start = start;
}
}
public List<int[]> getSkyline(int[][] buildings) {
// build ordered node list
ArrayList<Node> list = new ArrayList<Node>();
for (int[] building : buildings) {
Node node = new Node(building[0], building[2], true);
list.add(node);
node = new Node(building[1], building[2], false);
list.add(node);
}
Collections.sort(list, new Comparator<Node>() {
@Override
public int compare(Node left, Node right) {
// 1. x is larger
if (left.x != right.x)
return left.x - right.x;
// 2. not start
if (left.start != right.start)
return left.start ? -1 : 1;
// 3. left and right are all of the same x and same start, then
// compare y
return left.start ? right.y - left.y : left.y - right.y;
}
});
// traverse
List<int[]> result = new ArrayList<int[]>();
// key: height, value: rectangle number
TreeMap<Integer, Integer> map = new TreeMap<Integer, Integer>();
// last starting x and last y
int x = 0, y = 0;
for (Node node : list) {
if (node.start) {
// value
int newVal = map.containsKey(node.y) ? map.get(node.y) 1 : 1;
map.put(node.y, newVal);
// record for new height
if (node.y > y) {
x = node.x;
y = node.y;
result.add(new int[] { x, y });
}
} else {
// value--
Integer currentVal = map.get(node.y);
if (currentVal == 1) {
map.remove(node.y);
} else {
map.put(node.y, currentVal - 1);
}
// height==0
if (map.isEmpty()) {
x = node.x;
y = 0;
result.add(new int[] { x, 0 });
} else {
Integer last = (int) map.lastKey();
if (last != y) {
x = node.x;
y = last;
result.add(new int[] { x, y });
}
}
}
}
return result;
}
}
Contains Duplicate
【题目】Given an array of integers, find if the array contains any duplicates. Your function should return true if any value appears at least twice in the array, and it should return false if every element is distinct.
【解答】用一个 HashSet 来查重。
代码语言:javascript复制public class Solution {
public boolean containsDuplicate(int[] nums) {
if (null==nums)
return false;
Set<Integer> set = new HashSet<>();
for (int n : nums) {
if (set.contains(n))
return true;
set.add(n);
}
return false;
}
}
Combination Sum III
【题目】Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.
Ensure that numbers within the set are sorted in ascending order.
Example 1:
Input: k = 3, n = 7
Output:
代码语言:javascript复制[[1,2,4]]
Example 2:
Input: k = 3, n = 9
Output:
代码语言:javascript复制[[1,2,6], [1,3,5], [2,3,4]]
【解答】基本上就是回溯法解,出口有两个情况,一个是走到底了,没法再走了;还有一个是已经使用了全部的数了(参数 k),无法再加别的数了。
代码语言:javascript复制public class Solution {
public List<List<Integer>> combinationSum3(int k, int n) {
List<List<Integer>> total = new ArrayList<>();
if (k<=0 || n<=0)
return total;
com(new ArrayList<>(), 1, k, n, total);
return total;
}
private void com(List<Integer> list, int i, int k, int n, List<List<Integer>> total) {
if (i==10 || i>n || k==0)
return;
com(list, i 1, k, n, total);
List<Integer> newList = new ArrayList<>(list);
newList.add(i);
if (i==n && k==1)
total.add(newList);
else
com(newList, i 1, k-1, n-i, total);
}
}
Kth Largest Element in an Array
【题目】Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.
For example,
Given [3,2,1,5,6,4]
and k = 2, return 5.
Note:
You may assume k is always valid, 1 ≤ k ≤ array’s length.
【解答】要找第 k 大。当然可以排序,那样复杂度就是 n(log n),下面这个办法可以做到复杂度 n 阶,做法类似于快排,但是每次选择一个 pivot 之后,只需要看这个 pivot 的位置,如果正好是 k,那就皆大欢喜;如果比 k 大,那就说明需要继续迭代寻找左侧;如果比 k 小则是右侧。
代码语言:javascript复制public class Solution {
public int findKthLargest(int[] nums, int k) {
if (nums == null || k <= 0 || k > nums.length)
throw new IllegalArgumentException();
return search(nums, nums.length - k, 0, nums.length - 1);
}
public int search(int[] nums, int k, int left, int right) {
if (left >= right)
return nums[left];
int mid = partition(nums, left, right);
if (mid == k)
return nums[mid];
if (mid < k)
return search(nums, k, mid 1, right);
else
return search(nums, k, left, mid - 1);
}
public int partition(int[] nums, int left, int right) {
int x = nums[left];
int pivot = left;
int cur = left 1;
while (cur <= right) {
if (nums[cur] < x) {
pivot ;
swap(nums, pivot, cur);
}
cur ;
}
swap(nums, left, pivot);
return pivot;
}
private void swap(int[] nums, int left, int right) {
if (left == right)
return;
nums[left] ^= nums[right];
nums[right] ^= nums[left];
nums[left] ^= nums[right];
}
}
Shortest Palindrome
【题目】Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. Find and return the shortest palindrome you can find by performing this transformation.
For example:
Given "aacecaaa"
, return "aaacecaaa"
.
Given "abcd"
, return "dcbabcd"
.
【解答】需要考虑奇数回文串和偶数回文串两种情况。从需要补充的字符序列最少的情况开始考虑,逐步增加。迭代中首先确定疑似回文串的中心位置。
代码语言:javascript复制public class Solution {
public String shortestPalindrome(String s) {
if (s.length()==1)
return s;
int mid = s.length()/2;
for (int i=mid; i>=0; i--) {
String result = getPalindrome(s, i, false);
if (result!=null)
return result;
result = getPalindrome(s, i, true);
if (result!=null)
return result;
}
return null; // unreachable
}
private String getPalindrome(String s, int mid, boolean odd) {
String prepend = "";
int left;
int right;
if (odd) {
left = mid-2;
right = mid;
} else {
left = mid-1;
right = mid;
}
while (right<s.length()) {
if (left<0) {
prepend = s.charAt(right) prepend;
right ;
} else {
if (s.charAt(left) != s.charAt(right)) {
return null;
} else {
left--;
right ;
}
}
} // while
return prepend s;
}
}
House Robber II
【题目】Note: This is an extension of House Robber.
After robbing those houses on that street, the thief has found himself a new place for his thievery so that he will not get too much attention. This time, all houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, the security system for these houses remain the same as for those in the previous street.
Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.
【解答】基于 House Robber 的题目,这个街道现在变成了一个环。因此特殊的地方在于,首尾相邻,因此本来的递归出口现在没法成立了。于是这样考虑,设最末一个房子下标为 n,如果我分别看 0, n-1 和 1, n 这样两个区间,我可以保证这两个区间的情况下无论怎样抢劫,一定不会出现首尾都被抢的情况。于是给它们分别求得最大值,那么这两个最大值中的最大值,就为所求。
代码语言:javascript复制public class Solution {
public int rob(int[] nums) {
if (nums==null || nums.length==0)
return 0;
if (nums.length==1)
return nums[0];
Integer[] cache = new Integer[nums.length];
int res1 = rob1(nums, nums.length-2, cache);
cache = new Integer[nums.length];
int res2 = rob2(nums, nums.length-1, cache);
return Math.max(res1, res2);
}
private int rob1(int[] nums, int i, Integer[] cache) {
if (i==0)
return nums[i];
else if (i==1)
return Math.max(nums[0], nums[1]);
if (cache[i]!=null)
return cache[i];
int result = Math.max(rob1(nums, i-1, cache), rob1(nums, i-2, cache) nums[i]);
cache[i] = result;
return result;
}
private int rob2(int[] nums, int i, Integer[] cache) {
if (i==1)
return nums[i];
else if (i==2)
return Math.max(nums[2], nums[1]);
if (cache[i]!=null)
return cache[i];
int result = Math.max(rob2(nums, i-1, cache), rob2(nums, i-2, cache) nums[i]);
cache[i] = result;
return result;
}
}
Word Search II
【题目】Given a 2D board and a list of words from the dictionary, find all words in the board.
Each word must be constructed from letters of sequentially adjacent cell, where “adjacent” cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.
For example,
Given words = ["oath","pea","eat","rain"]
and board =
[
['o','a','a','n'],
['e','t','a','e'],
['i','h','k','r'],
['i','f','l','v']
]
Return ["eat","oath"]
.
Note:
You may assume that all inputs are consist of lowercase letters a-z
.
【解答】大体上有两种思路,一种是把 words 数组里面的每个单词取出来,分别到 board 里面去找;另一种是把 board 里面的单词取出来,挨个去 words 里面找。我采用的是后一种。但是,直接匹配的效率肯定过低,所以把 words 根据之前 Trie 树的经验,构造成一棵大的 Trie 树,然后以 board 里面以每一个元素作为单词起点,到这棵大 Trie 树中去匹配,优先考虑前缀匹配,如果前缀匹配失败,就不需要继续往下走了;如果匹配成功,再考虑完整单词匹配。
代码语言:javascript复制class TrieNode {
public char ch;
public Map<Character, TrieNode> subs = new HashMap<Character, TrieNode>();
// Initialize your data structure here.
public TrieNode() {
}
}
class Trie {
private TrieNode root;
public Trie() {
root = new TrieNode();
}
// Inserts a word into the trie.
public void insert(String word) {
if (null == word)
throw new IllegalArgumentException();
TrieNode node = root;
for (int i = 0; i < word.length(); i ) {
char ch = word.charAt(i);
if (!node.subs.containsKey(ch)) {
TrieNode newNode = new TrieNode();
newNode.ch = ch;
node.subs.put(ch, newNode);
}
node = node.subs.get(ch);
}
node.subs.put('