切题四件套
Clarification、Possible solutions、Coding、Test cases
常用数据结构
数组、链表、队列、栈、堆、哈希表、树、二叉查找树、字母树、LRU缓存
常用算法
递归、贪心、分治、广度优先搜索、深度优先搜索、二叉树遍历、动态规划、二分查找、图
时间/空间复杂度
O(1)、O(logn)、O(n)、O(nlogn)、O(n2)、O(n3)、O(2n)、O(n!)
常见算法复杂度
二分查找:O(logn)、二叉树遍历:O(n)、归并排序:O(nlogn)
做题之前一定要想时间/空间复杂度
Map | put | get | remove | containsKey | keySet | entrySet | clear | isEmpty | size |
---|---|---|---|---|---|---|---|---|---|
Collection | add | addAll | remove | removeAll | contains | containsAll | clear | isEmpty | size |
Set | |||||||||
List | get | ||||||||
Stack | push | peek | pop | ||||||
Queue | add | peek | poll | ||||||
Deque | addFrist addLast | peekFirst peekLast | pollFirst pollLast |
String:charAt、toCharArray、Arrays.sort、valueOf
涉及到获取操作一定要想到判空
LinkedList 实现了 List、Queue、Deque
二分查找:(单调递增或递减、存在上下界、能够通过索引访问)
class Solution {
fun search(nums: IntArray, target: Int): Int {
if (nums.size == 0) return -1
var start = 0
var end = nums.size - 1
var middle = 0
while (start <= end) {
middle = (start + end) / 2
when {
nums[middle] == target -> {
return middle
}
nums[middle] > target -> {
end = middle - 1
}
else -> {
start = middle + 1
}
}
}
return -1
}
}
反转链表:只要保证cur不为空
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
ListNode nex = null;
while(cur != null) {
nex = cur.next;
cur.next = pre;
pre = cur;
cur = nex;
}
return pre;
}
}
两两交换链表:需要记录四个节点
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null) return head;
ListNode ret = head.next;
ListNode pre = null;
ListNode cur0 = head;
ListNode cur1 = head.next;
ListNode next = null;
while(cur0 != null && cur1 != null) {
next = cur1.next;
if(pre != null) pre.next = cur1;
cur1.next = cur0;
cur0.next = next;
pre = cur0;
cur0 = next;
cur1 = (cur0 != null) ? cur0.next : null;
}
return ret;
}
}
环形链表:HashSet、快慢指针
public class Solution {
public boolean hasCycle(ListNode head) {
// if(head == null) return false;
// ListNode cur = head;
// HashSet<ListNode> hashSet = new HashSet<>();
// while(cur != null) {
// if(hashSet.contains(cur)) return true;
// hashSet.add(cur);
// cur = cur.next;
// }
// return false;
ListNode low = head, fast = head;
while(fast != null) {
low = low.next;
fast = fast.next;
if(fast == null) return false;
fast = fast.next;
if(fast == low) return true;
}
return false;
}
}
K个一组翻转链表:
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if(k <= 1 || head == null) return head;
ListNode res = head;
ListNode cur = head;
ListNode pre = null;
Stack<ListNode> stack = new Stack<>();
while(cur != null) {
for(int i = 0; i < k; i++) {
if(cur != null) {
stack.push(cur);
cur = cur.next;
} else {
return res;
}
}
if(stack.size() == k && res == head) {
res = stack.peek();
}
for(int i = 0; i < k; i++) {
if(pre != null) {
pre.next = stack.peek();
}
pre = stack.pop();
}
if(pre != null) {
pre.next = cur;
}
}
return res;
}
}
统一规律:在循环内部赋值,尽量减少循环判断的参数信息
有效的括号:需要后面的括号作为Key、需要实时判断栈是否为空
class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
Map<Character, Character> map = new HashMap<>();
map.put(')', '(');
map.put('}', '{');
map.put(']', '[');
for (int i = 0; i < s.length(); i++) {
if(!map.containsKey(s.charAt(i))) {
stack.push(s.charAt(i));
} else {
//忘记判断栈是否为空了
if(stack.isEmpty()) return false;
if(!stack.pop().equals(map.get(s.charAt(i)))) return false;
}
}
return stack.isEmpty();
}
}
两个队列实现栈、两个栈实现队列
优先队列(PriorityQueue):Heap、Binary Search Tree
小顶堆:父亲比左右孩子都要小
二叉堆 | find-min:O(1) | delete-min:O(logn) | insert:O(logn) | merge:O(n) |
---|---|---|---|---|
Fibonacci堆 | find-min:O(1) | delete-min:O(logn) | insert:O(1) | merge:O(1) |
返回数据流中第K大的元素:小顶堆O(Nlogk)、排序O(Nklogk)
class KthLargest {
private Queue<Integer> queue = null;
private int size = 0;
public KthLargest(int k, int[] nums) {
queue = new PriorityQueue<Integer>(k, new Comparator<Integer>() {
@Override
public int compare(Integer i, Integer j) {
return i.compareTo(j);
}
});
size = k;
for(int i = 0; i < nums.length; i++) {
add(nums[i]);
}
}
public int add(int val) {
if(queue.size() < size) {
queue.add(val);
} else {
if(!queue.isEmpty() && val > queue.peek()) {
queue.poll();
queue.add(val);
}
}
return queue.peek();
}
}
PriorityQueue默认是小顶堆,我们需要手动实现Comparator来实现大顶堆
priorityQueue = new PriorityQueue<Integer>(k, new Comparator<Integer>() {
@Override
public int compare(Integer i1, Integer i2) {
return i2.compareTo(i1);
}
});
滑动窗口最大值:Deque(双端队列)
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums.length <= 0 || k <= 0 || nums.length < k) return new int[0];
Deque<Integer> deque = new LinkedList<>();
int res[] = new int[nums.length - k + 1];
for (int i = 0; i < nums.length; i++) {
if (!deque.isEmpty()) {
if (i >= k && deque.peekFirst() <= i - k) deque.pollFirst();
while(!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) deque.pollLast();
}
deque.addLast(i);
if (i >= k - 1) res[i - k + 1] = nums[deque.peekFirst()];
}
return res;
}
}
有效的字母异或位:排序O(nlogn)、字母计数O(n)
class Solution {
public boolean isAnagram(String s, String t) {
if(s == null && t == null) return true;
if(s == null || t == null) return false;
char[] ss = s.toCharArray();
char[] ts = t.toCharArray();
Arrays.sort(ss);
Arrays.sort(ts);
return String.valueOf(ss).equals(String.valueOf(ts));
}
}
Integer和Integer之间不能用等号进行判断,Integer和int之间可以
二数之和:暴力循环、HashMap
三数之和:排序之后可以很好的排除相同元素
四数之和:多了一层循环
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
if(nums.length < 3) return new LinkedList<>();
List<List<Integer>> result = new LinkedList<>();
Arrays.sort(nums);
for(int i = 0; i < nums.length - 2; i++) {
if(i != 0 && nums[i-1] == nums[i]) continue;
int j = i + 1, k = nums.length - 1;
while(j < k) {
int sum = nums[i] + nums[j] + nums[k];
if(sum == 0) result.add(Arrays.asList(nums[i], nums[j], nums[k]));
if(sum <= 0) do j++; while(j < k && nums[j] == nums[j - 1]);
if(sum >= 0) do k--; while(j < k && nums[k] == nums[k + 1]);
}
}
return result;
}
}
二叉搜索树:指一棵空树或者具有下列性质的二叉树(左子树上所有节点小于根节点、右子树上所有节点大于根节点、左右子树也分别为二叉搜索树)
平衡二叉搜索树:Red-Black Tree,最坏情况也是O(logN)
验证二叉搜索树:中序遍历、双层递归
二叉搜索树的最近公共祖先:根据值来判断
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || (p == null && q == null)) {
return root;
} else if(p == null) {
return q;
} else if(q == null) {
return p;
} else if (root.val > p.val && root.val > q.val) {
return lowestCommonAncestor(root.left, p, q);
} else if (root.val < p.val && root.val < q.val) {
return lowestCommonAncestor(root.right, p, q);
} else {
return root;
}
}
}
二叉树的最近公共祖先:
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null || p == null || q == null) return null;
if(root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
return (left != null && right != null) ? root : left != null ? left : right;
}
}
遍历二叉树(前序、中序、后序)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<Integer> preOrderTraversal(TreeNode root) {
//traversal
List<Integer> list = new LinkedList<Integer>();
if(root == null) return list;
list.add(root.val);
list.addAll(preorderTraversal(root.left));
list.addAll(preorderTraversal(root.right));
return list;
//non-traversal
List<Integer> list = new LinkedList<Integer>();
if (root == null) return list;
Stack<TreeNode> stack = new Stack<>();
stack.add(root);
while (!stack.isEmpty()) {
TreeNode cur = stack.pop();
list.add(cur.val);
//这里不要糊涂,应该是右孩子先进栈
if (cur.right != null) stack.push(cur.right);
if (cur.left != null) stack.push(cur.left);
}
return list;
}
public List<Integer> inOrderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
List<Integer> list = new LinkedList<>();
if(root == null) return list;
TreeNode cur = root;
//如果cur不为空,一直往左压栈,访问栈顶,右孩子入栈
while(!stack.isEmpty() || cur != null) {
while(cur != null) {
stack.push(cur);
cur = cur.left;
}
cur = stack.pop();
list.add(cur.val);
cur = cur.right;
}
return list;
}
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
TreeNode lastVisit = null;
while(!stack.isEmpty() || cur != null) {
while(cur != null) {
stack.push(cur);
cur = cur.left;
}
cur = stack.peek();
if (cur.right == null || cur.right == lastVisit) {
list.add(cur.val);
lastVisit = stack.pop();
cur = null;
} else {
cur = cur.right;
}
}
return list;
}
}
递归分治:Pow(x, n),需要注意的是负数转正数需要考虑边界值(Integer.MIN_VALUE)
class Solution {
public double myPow(double x, int n) {
double pow = 1;
if(n < 0) {
if(n == Integer.MIN_VALUE){
x = 1 / x;
n = -(n + 1);
pow = x;
} else {
x = 1 / x;
n = -n;
}
}
while(n != 0) {
if((n & 1) == 1) {
pow = pow * x;
}
x *= x;
n >>= 1;
}
return pow;
// if(n < 0) return (n != Integer.MIN_VALUE) ? 1 / myPow(x, -n) : 1 / (x * myPow(x, -(n+1)));
// if(n == 0) return 1;
// double tmp = myPow(x, n/2);
// return (n % 2 == 0) ? tmp * tmp : x * tmp * tmp;
}
}
求众数:排序、HashMap
class Solution {
public int majorityElement(int[] nums) {
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < nums.length; i++) {
if(map.containsKey(nums[i])) {
map.put(nums[i], map.get(nums[i]) + 1);
} else {
map.put(nums[i], 1);
}
}
int max = 0;
int res = 0;
for(Integer i : map.keySet()) {
if(map.get(i) > max) {
max = map.get(i);
res = i;
}
}
return res;
}
}
二叉树的层次遍历:BFS(广度优先搜索):队列实现、DFS(深度优先搜索):需要传递层次信息
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> list = new LinkedList<>();
levelOrder(root, 0, list);
return list;
}
private void levelOrder(TreeNode root, int level, List<List<Integer>> list) {
if(root == null) return;
if(level > list.size() - 1) list.add(new LinkedList<Integer>());
list.get(level).add(root.val);
levelOrder(root.left, level + 1, list);
levelOrder(root.right, level + 1, list);
}
}
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> list = new LinkedList<>();
if(root == null) return list;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()) {
int size = queue.size();
List<Integer> list_item = new LinkedList<>();
for(int i = 0; i < size; i++) {
TreeNode tmp = queue.poll();
list_item.add(tmp.val);
if(tmp.left != null) queue.add(tmp.left);
if(tmp.right != null) queue.add(tmp.right);
}
list.add(list_item);
}
return list;
}
}
二叉树的最大/最小深度:广度优先搜索、深度优先搜索(递归,可以看成中序遍历)
括号生成:(深度优先 + 剪枝算法)
class Solution {
public List<String> generateParenthesis(int n) {
List<String> list = new LinkedList<>();
generate(list, 0, 0, n, "");
return list;
}
//要点在于参数是值传递,可以回溯
private void generate(List<String> list, int left, int right, int n, String result) {
if (left == n && right == n) list.add(result);
if (left < n) generate(list, left + 1, right, n, result + "(");
if (right < n && right < left) generate(list, left, right + 1, n, result + ")");
}
}
剪枝:递归前面加上判断条件
N皇后问题(DFS+剪枝):
class Solution {
private Set<Integer> cols = new HashSet<>();
private Set<Integer> pie = new HashSet<>();
private Set<Integer> na = new HashSet<>();
private List<List<String>> results = new LinkedList<>();
public List<List<String>> solveNQueens(int n) {
DFS(0, n, new LinkedList<String>());
return results;
}
private void DFS(int row, int n, List<String> res) {
if(row >= n) {
List<String> result = new LinkedList<>();
result.addAll(res);
results.add(result);
return;
}
for(int col = 0; col < n; col++) {
if(cols.contains(col) || pie.contains(row + col) || na.contains(row - col)) continue;
StringBuilder sb = new StringBuilder();
for(int s = 0; s < n; s++) {
if(s != col) sb.append("."); else sb.append("Q");
}
res.add(sb.toString());
cols.add(col);
pie.add(row + col);
na.add(row - col);
DFS(row + 1, n, res);
res.remove(sb.toString());
cols.remove(col);
pie.remove(row + col);
na.remove(row - col);
}
}
}
有效的数独(利用9个数的特性):
class Solution {
public boolean isValidSudoku(char[][] board) {
boolean[][] row = new boolean[9][10];
boolean[][] col = new boolean[9][10];
boolean[][] block = new boolean[9][10];
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
if(board[i][j] != '.') {
int num = board[i][j] - '0';
if(row[i][num] || col[j][num] || block[i / 3 * 3 + j / 3][num]) {
return false;
} else {
row[i][num] = true;
col[j][num] = true;
block[i / 3 * 3 + j / 3][num] = true;
}
}
}
}
return true;
}
}
解数独(DFS+剪枝):
class Solution {
public void solveSudoku(char[][] board) {
DFS(board, 0, 0);
}
private boolean DFS(char[][] board, int i, int j) {
if(i == (9 - 1) && j == (9 - 1) && board[i][j] != '.') return true;
while(true) {
if(board[i][j] == '.') {
break;
} else {
if(j < 9 - 1) {
j++;
} else {
if(i < 9 - 1) {
i++;
j = 0;
} else {
return true;
}
}
}
}
for(char num = '1'; num <= '9'; num++) {
if(isValid(board, i, j, num)) {
board[i][j] = num;
if(DFS(board, i, j)) {
return true;
} else {
board[i][j] = '.';
}
}
}
return false;
}
private boolean isValid(char[][] board, int row, int col, char num) {
for(int i = 0; i < 9; i++) {
if(board[row][i] != '.' && board[row][i] == num) return false;
if(board[i][col] != '.' && board[i][col] == num) return false;
if(board[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] != '.' &&
board[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] == num) return false;
}
return true;
}
}
X的平方根(多层的二分查找):
class Solution {
public int mySqrt(int x) {
double res = mySqrt(x, 1);
return (int)res;
}
private double mySqrt(int x, int precise) {
double left = 0;
double right = x;
double incre = 1;
for(int i = 0; i < precise; i++) {
while(left < right) {
double mid = (right + left) / 2;
mid = (double)((int)(mid * (1 / incre))) / (1 / incre);
double tmp = mid * mid;
if(tmp > x) right = mid - incre;
if(tmp < x) left = left + incre;
if(tmp == x) return mid;
}
left = left * left > x ? left - incre : left;
right = left + incre;
incre /= 10;
}
return left;
}
}
Trie树(字典树):又称单次查找树或键树
class Trie {
class TrieNode {
public boolean isWord = false;
public TrieNode[] children = new TrieNode[26];
public TrieNode() {
}
}
TrieNode root = null;
public Trie() {
root = new TrieNode();
}
public void insert(String word) {
}
public void search(String word) {
}
public boolean search(String word) {
}
}
单词搜索:(DFS+位置记录+单词前缀剪枝)
位运算 | & | | | ^ | ~ | >> | << | >>> |
---|
X = X & (X - 1):清零最低位的1
判断一个数是否是2的幂:
class Solution {
public boolean isPowerOfTwo(int n) {
return n <= 0 ? false : (n & (n - 1)) == 0;
}
}
判断数组中各个数1的位数:
class Solution {
public int[] countBits(int num) {
int[] res = new int[num + 1];
for(int i = 1; i < num + 1; i++) {
res[i] = res[i & (i - 1)] + 1;
}
return res;
}
}
螺旋矩阵:
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> list = new LinkedList<>();
int i = 0, j = 0, m = matrix.length, n = 0;
if(m > 0) n = matrix[0].length;
spiralOrder(matrix, 0, 0, m - 1, n - 1, list);
return list;
}
private void spiralOrder(int[][] matrix, int i, int j, int m, int n, List<Integer> list) {
if(i > m || j > n) {
return;
} else if(i == m && j == n) {
list.add(matrix[i][j]);
} else if(i == m) {
for(int s = j; s <= n; s++) {
list.add(matrix[i][s]);
}
} else if(j == n) {
for(int s = i; s <= m; s++) {
list.add(matrix[s][j]);
}
} else {
for(int s = j; s < n; s++) {
list.add(matrix[i][s]);
}
for(int s = i; s < m; s++) {
list.add(matrix[s][n]);
}
for(int s = n; s > j; s--) {
list.add(matrix[m][s]);
}
for(int s = m; s > i; s--) {
list.add(matrix[s][j]);
}
}
spiralOrder(matrix, i+1, j+1, m-1, n-1, list);
}
}
动态规划(Dynamic Programming)
- 递归(自上向下)+ 记忆化 -> 递推(自下而上)
- 状态的定义
- 状态转移方程
- 最优子结构
爬楼梯:最简单的动态规划(状态定义简单、DP方程简单)
三角形的最小路径和:(状态定义简单、DP方程简单)
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int height = triangle.size();
int[] memory = new int[height + 1];
for(int i = height - 1; i >= 0; i--) {
for(int j = 0; j <= i; j++) {
memory[j] = Math.min(memory[j], memory[j + 1]) + triangle.get(i).get(j);
}
}
return memory[0];
}
}
乘积最大子序列:(状态定义困难、DP方程简单、存在截断问题,需要循环搜索最优解)
class Solution {
public int maxProduct(int[] nums) {
int max = Integer.MIN_VALUE, imax = 1, imin = 1; //一个保存最大的,一个保存最小的。
for(int i=0; i<nums.length; i++){
if(nums[i] < 0){ int tmp = imax; imax = imin; imin = tmp;}
//和nums[i]比较就是截断的过程
imax = Math.max(imax*nums[i], nums[i]);
imin = Math.min(imin*nums[i], nums[i]);
max = Math.max(max, imax);
}
return max;
}
}
最长上升子序列:复杂度O(n2)
class Solution {
public int lengthOfLIS(int[] nums) {
if(nums.length <= 0) return 0;
int[] lengths = new int[nums.length];
lengths[0] = 1;
for(int i = 1; i < nums.length; i++) {
int max = 0;
for(int j = 0; j < i; j++) {
max = nums[j] < nums[i] ? (lengths[j] > max ? lengths[j] : max) : max;
}
lengths[i] = max + 1;
}
int length = 0;
for(int i = 0; i < lengths.length; i++) {
length = lengths[i] > length ? lengths[i] : length;
}
return length;
}
}
零钱兑换(变相的爬楼梯):
class Solution {
public int coinChange(int[] coins, int amount) {
int[] nums = new int[amount + 1];
for(int i = 0; i <= amount; i++) nums[i] = Integer.MAX_VALUE;
nums[0] = 0;
for(int i = 1; i <= amount; i++) {
for(int j = 0; j < coins.length; j++) {
if(i - coins[j] < 0 || nums[i - coins[j]] == Integer.MAX_VALUE) continue;
if(nums[i - coins[j]] + 1 < nums[i]) nums[i] = nums[i - coins[j]] + 1;
}
}
return nums[amount] == Integer.MAX_VALUE ? -1 : nums[amount];
}
}
股票买卖问题(只能买卖一次):
class Solution {
public int maxProfit(int[] prices) {
if(prices.length < 2) return 0;
int min = prices[0];
int profit = 0;
for(int i = 1; i < prices.length; i++) {
if(prices[i] - min > profit) profit = prices[i] - min;
if(prices[i] < min) min = prices[i];
}
return profit;
}
}
股票买卖问题(无数次):代码略
股票买卖问题(带冷却时间):
股票买卖问题(带手续费):
股票买卖问题(最多K笔交易):
for (int i = 0; i < n; i++) { //天数
for (int k = 0; k < K; k++) { //交易次数
dp[i][0][k] = MAX{ dp[i - 1][0][k], dp[i - 1][1][k - 1] + a[i] };
dp[i][1][k] = MAX{ dp[i - 1][1][k], dp[i - 1][0][k] - a[i] };
}
}
//最终结果在 dp[n - 1][0...k][0] 中
编辑距离(状态定义困难、DP转移方程一般):DP[i][j](word1前i个字符替换word2前j个字符的最少步数)
class Solution {
public int minDistance(String word1, String word2) {
if(word1 == null && word2 == null) return 0;
if(word1 == null || word2 == null) return Integer.MAX_VALUE;
int length1 = word1.length();
int length2 = word2.length();
int[][] matrix = new int[length1 + 1][length2 + 1];
for(int i = 0; i <= length1; i++) matrix[i][0] = i;
for(int i = 0; i <= length2; i++) matrix[0][i] = i;
for(int i = 1; i <= length1; i++) {
for(int j = 1; j <= length2; j++) {
if(word1.charAt(i - 1) == word2.charAt(j - 1)) {
matrix[i][j] = matrix[i - 1][j - 1];
} else {
matrix[i][j] = Math.min(Math.min(matrix[i - 1][j], matrix[i][j - 1]), matrix[i - 1][j - 1]) + 1;
}
}
}
return matrix[length1][length2];
}
}
LRU Cache(Least Recently Used):最近使用的替掉最少使用的,通过LinkedHashMap实现(能保证插入顺序,get访问效率也高),重写removeEldestEntry方法来实现自动删除最老的元素
LFU(Least Frequence Used):最近使用的替掉频率最低的
KMP算法(strStr)
class Solution {
public int strStr(String haystack, String needle) {
if(needle == null || needle.equals("")) return 0;
if(haystack == null) return -1;
if(needle.length() > haystack.length()) return -1;
int[] next = getNext(needle);
int i = 0;
int j = 0;
char[] chars1 = haystack.toCharArray();
char[] chars2 = needle.toCharArray();
while(i < chars1.length && j < chars2.length) {
if(j == -1 || chars1[i] == chars2[j]) {
i++;
j++;
} else {
j = next[j];
}
}
if(j == chars2.length)
return i - j;
else
return -1;
}
int[] getNext(String needle) {
char[] chars = needle.toCharArray();
int[] next = new int[chars.length];
next[0] = -1;
int m = -1;
int n = 0;
while(n < chars.length - 1) {
if(m == -1 || chars[m] == chars[n]) {
m++;
n++;
next[n] = m;
} else {
m = next[m];
}
}
return next;
}
}
区间合并(需要排序,选用的快排):
class Solution {
public List<Interval> merge(List<Interval> intervals) {
if(intervals == null || intervals.size() < 2) return intervals;
int length = intervals.size();
int[][] res = new int[length][2];
for(int i = 0; i < length; i++) {
res[i][0] = intervals.get(i).start;
res[i][1] = intervals.get(i).end;
}
sort(res, 0, res.length - 1);
List<Interval> list = new LinkedList<>();
int[][] tmp = new int[length][2];
tmp[0] = res[0];
int tmp_length = 1;
for(int i = 1; i < length; i++) {
if(res[i][1] <= tmp[tmp_length - 1][1]) {
continue;
} else if(res[i][0] <= tmp[tmp_length - 1][1] && res[i][1] >= tmp[tmp_length - 1][1]) {
tmp[tmp_length - 1][1] = res[i][1];
} else {
tmp_length++;
tmp[tmp_length - 1][0] = res[i][0];
tmp[tmp_length - 1][1] = res[i][1];
}
}
for(int i = 0; i < tmp_length; i++) {
list.add(new Interval(tmp[i][0], tmp[i][1]));
}
return list;
}
private void sort(int[][] intervals, int i, int j) {
if(i < j) {
int base0 = intervals[i][0];
int base1 = intervals[i][1];
while(i < j) {
while(i < j && intervals[j][0] >= base0) j--;
intervals[i][0] = intervals[j][0];
intervals[i][1] = intervals[j][1];
while(i < j && intervals[i][0] <= base0) i++;
intervals[j][0] = intervals[i][0];
intervals[j][1] = intervals[i][1];
}
intervals[i][0] = base0;
intervals[i][1] = base1;
sort(intervals, 0, i - 1);
sort(intervals, i + 1, j);
}
}
}
求K个无序数组的中位数:小顶堆、快速排序
求字符串的Huffman编码:频率排序,生成父节点之后重新计算频率,可以通过小顶堆来实现
求两个有序数组所有数中第K大的数、求两个有序数组所有数的中位数:二分查找,对应第二个数组截成两段,比较临界值
数组的最大区间和:动态规划,类似于最大乘积子序列
单向链表最后第K个节点:双指针实现,不需要回溯
判断二叉树是否是完全二叉树(不是满二叉树):层次遍历 + 逐层判断
判断二叉树是否是满二叉树:2的N次方 - 1
求两个链表的交叉节点:计算两个链表的长度差,然后长的链表先后移、通过HashSet来判断
对数组中的元素进行重新排列,负数放到前面,不改变相对顺序:一遍快排
求数组中逆序对的个数:归并排序 //TODO
统计字符串中出现最多的字符和次数:HashMap、String.toCharArray
排序算法总结:各种排序算法总结和比较 - 苍穹逸影 - 博客园
稳定排序算法:插入排序、冒泡排序、归并排序
不稳定排序算法:选择排序(5 8 5 2 9)、希尔排序、快速排序、堆排序
斜45度打印数组:数字游戏,需要补全
有序数组中任选两个数之和等于目标值,给出所有组合:HashSet
和至少为K的最短子数组:双层(起点循环)+ 动态规划
对称树判断:
public boolean isMirror(TreeNode t1, TreeNode t2) {
if (t1 == null && t2 == null) return true;
if (t1 == null || t2 == null) return false;
return (t1.val == t2.val)
&& isMirror(t1.right, t2.left)
&& isMirror(t1.left, t2.right);
}
public boolean isSymmetric(TreeNode root) {
Queue<TreeNode> q = new LinkedList<>();
q.add(root);
q.add(root);
while (!q.isEmpty()) {
TreeNode t1 = q.poll();
TreeNode t2 = q.poll();
if (t1 == null && t2 == null) continue;
if (t1 == null || t2 == null) return false;
if (t1.val != t2.val) return false;
q.add(t1.left);
q.add(t2.right);
q.add(t1.right);
q.add(t2.left);
}
return true;
}
二叉树转换成单链表: