举例法,模式匹配法,简化推广法,简单构造法,数据结构头脑风暴
很多题目都是需要out of box的想法
递归除了跟动态规划结合,还可以升级成回溯法,回溯法的递归基有时要按照规则进行。
横向纵向数组都有序,查找某个元素
从左下角开始查找
top 每一个题目都有记录
买股票的5个问题
121. Best Time to Buy and Sell Stock
思路: 出现最小更新最小,否则更新最大利润。只进行第一次操作(买和卖)
122. Best Time to Buy and Sell Stock II
不限制操作次数
思路:1.贪心问题,如果后面比前面大,就把差值加上
2.找到波谷波峰,波谷买入,波峰卖出
309. Best Time to Buy and Sell Stock with Cooldown
思路:动态规划,给定三个状态,对值进行确定。画出三个状态以及状态之间的转移图即可得出状态转移方程。这个是简单的一维动态规划。
123. Best Time to Buy and Sell Stock III
要求:给定输入只能有两次交易,得到最大金额,更加泛华的解法看下一题,有k次交易的机会
188. Best Time to Buy and Sell Stock IV
要求:只有k完整交易机会,只有买和卖两种状态,然后构建两个二维数组,第二个二维数组的长度为k+1
ac:trick 1.只有在sell时才是一次完整的交易,
2.初始化时候buy[i][0] 和 buy[0][k] 的赋值,
3.sell[0][k] 的赋值
到此,买股票问题全部解决
171. Excel Sheet Column Number
ac: 本质上是26进制转换问题
链表的几个类似的问题
237. Delete Node in a Linked List
要求:删除一个元素,但是只给你当前元素的结点
ac:将下一个的值赋值给当前的元素,然后删除下一个元素
203. Remove Linked List Elements
错误:只是用一个指针,无法删除形如[1,1],这样的最后一个元素
ac:利用dummy,加上两个指针。
147. Insertion Sort List
要求:实现链表的插入排序,
412. Fizz Buzz整除3,输出Fizz,整除5 ,输出Fuzz,整除3和5输出FizzFuzz
最优解,搞两个参数,每次处理后自动清零
108. Convert Sorted Array to Binary Search Tree
递归解决
454. 4Sum II
4个数组,每个数组取出一个数,只要和为0,就满足需求,输出多少种组合。
最优解: O(n平方),先对AB的和用Map进行缓存,然后对CD和取出,看看能否拼成0
map.put(sum, map.getOrDefault(sum, 0) + 1);
378. Kth Smallest Element in a Sorted Matrix
行升序,列升序,得到特定序号的值
思路:原来是打算构建完整的优先队列,这个不需要,只是对x + 1进行入队列即可,不
public class Solution {
public int kthSmallest(int[][] matrix, int k) {
int n = matrix.length;
PriorityQueue<Tuple> pq = new PriorityQueue<Tuple>();
for(int j = 0; j <= n-1; j++) pq.offer(new Tuple(0, j, matrix[0][j]));
for(int i = 0; i < k-1; i++) {
Tuple t = pq.poll();
if(t.x == n-1) continue;
pq.offer(new Tuple(t.x+1, t.y, matrix[t.x+1][t.y]));
}
return pq.poll().val;
}
}
class Tuple implements Comparable<Tuple> {
int x, y, val;
public Tuple (int x, int y, int val) {
this.x = x;
this.y = y;
this.val = val;
}
@Override
public int compareTo (Tuple that) {
return this.val - that.val;
}
}
//二分查找,感觉有点不科学,时间复杂度较高
public class Solution {
public int kthSmallest(int[][] matrix, int k) {
int lo = matrix[0][0], hi = matrix[matrix.length - 1][matrix[0].length - 1] + 1;//[lo, hi)
while(lo < hi) {
int mid = lo + (hi - lo) / 2;
int count = 0, j = matrix[0].length - 1;
for(int i = 0; i < matrix.length; i++) {
while(j >= 0 && matrix[i][j] > mid) j--;
count += (j + 1);
}
if(count < k) lo = mid + 1;
else hi = mid;
}
return lo;
}
}// 虽然没有直接进行比较,但是通过count的数值进行了比较,这个二分取得是最左边第一个满足条件的数
22. Generate Parentheses
括号匹配的问题,用递归来实现
根据正反括号的个数进行匹配
不使用StringBuffer反而更快,这个是包装类,传送的是地址。由于String存在的唯一性,内部自己实现复制
230. Kth Smallest Element in a BST
思路:2种时间复杂度低的方法,一个是二叉树的递归遍历,一个是非递归版本中序遍历,
非递归版本的遍历需要注意的是k–,不用新建变量
//递归版本的解法
public class Solution {
private static int count;
private static int val;
public int kthSmallest(TreeNode root, int k) {
this.count = k;
helper(root);
return val;
}
public void helper(TreeNode root) {
if (root.left != null) {
helper(root.left);
}
count--;
if (count == 0) {
this.val = root.val;
}
if (root.right != null){
helper(root.right);
}
}
}
328. Odd Even Linked List
将链表处于奇数个的位置连起来,然后将处于偶数个的位置连起来,奇数尾部跟着第一个偶数
思路: 两个指针,形同删除,最后连接
287. Find the Duplicate Number
给定n + 1个数, 数的范围为1到n
思路:快行指针,与循环链表的类似,
最优解:对当前数组下标立面的数编程负的
public class Solution {
public int findDuplicate(int[] nums) {
if (nums.length > 1) {
int slow = nums[0];
int fast = nums[nums[0]];
while (slow != fast){
slow = nums[slow];
fast = nums[nums[fast]];
}
fast = 0;
while (slow != fast) {
fast = nums[fast];
slow = nums[slow];
}
return slow;
}
return -1;
}
}
46. Permutations
Given a collection of distinct numbers, return all possible permutations.
给出一数组的所有线性排列组合,数组中的数都不重复
思路: 1。回溯法,利用递归实现
2.交换法,交换数组中的数,最后方法列表中去
3.插入法 , 例如只有1 , 加上 2 就是 1, 2;2, 1复制的数比较多,
//回溯法(递归里面的一种)典型的形式,需要在递归后对链表数据进行删除
public class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> list = new LinkedList<>();
List<Integer> templist = new LinkedList<>();
backTrack(list, templist, nums, 0);
return list;
}
public void backTrack(List<List<Integer>> list, List<Integer> templist, int[] nums, int len) {
if (len == nums.length) {
list.add(new LinkedList<Integer>(templist));
return;
} else {
for (int i = 0; i < nums.length; i++) {
if (templist.contains(nums[i])) {
continue;
}
templist.add(nums[i]);
backTrack(list, templist, nums, len + 1);
templist.remove(templist.size() - 1);
}
}
}
}
//还有一种是交换的方法,这里暂时不是。java不可以直接添加数组
//第三种方法,插入法
public class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> list = new ArrayList<List<Integer>>();
List<Integer> temp = new ArrayList<Integer>();
temp.add(nums[0]);
list.add(temp);
for (int i = 1; i < nums.length; i++) {
List<List<Integer>> tempres = new ArrayList<List<Integer>>();
for (int j = 0; j <= i; j++) {
for (List<Integer> l : list) {
List<Integer> sigl = new ArrayList<Integer>(l);
sigl.add(j, nums[i]);
tempres.add(sigl);
}
}
list = tempres;
}
return list;
}
}
47. Permutations II Given a collection of numbers that might contain duplicates, return all possible unique permutations.
存在重复元素
if(used[i] || i > 0 && nums[i] == nums[i-1] && !used[i - 1]) continue;
78. Subsets
90. Subsets II Given a collection of integers that might contain duplicates, nums, return all possible subsets.
if(i > start && nums[i] == nums[i-1]) continue; // skip duplicates//因为先进行过排序操作了
62. Unique Paths
m * n的棋盘,从左上角到右下角,多少种不同的路径,只能向下或者向右。
思路: 1直接公式计算
2。迭代加动态规划,设计一个m*n的数组,在处理时,用上面的点加左面点的路径之和,与爬楼梯相似
public class Solution {
public int uniquePaths(int m, int n) {
int[][] arr = new int[m][n];
for (int i = 0; i < m; i++) {
arr[i][0] = 1;
}
for (int j = 0; j < n; j++) {
arr[0][j] = 1;
}
for (int x = 1; x < m; x++) {
for (int y = 1; y < n; y++){
arr[x][y] = arr[x - 1][y] + arr[x][y - 1];
}
}
return arr[m - 1][n - 1];
}
}
341. Flatten Nested List Iterator
Given a nested list of integers, implement an iterator to flatten it.Each element is either an integer, or a list – whose elements may also be integers or other lists.
思路:给定一个实现类,现在要实现iterator迭代器。hasnext 与 next, 这个地方采用的是stack进行缓存,重点在于hasnext将list转换为integer
380. Insert Delete GetRandom O(1)
设计一个数据结构,实现O(1)时间复杂度的插入元素,删除元素,以及获取其中的随机个数。
ArrayList 与 HashMap的结合
215. Kth Largest Element in an Array
给定无序数组,找到最大的第K个数
思路: 1. 先排序
2. 小顶堆,找到第k个大的数用小顶堆,找到第k个小的数,用大顶堆。
3. 选择排序,快排
300. Longest Increasing Subsequence
这个题目以前刷过这个经典的算法
//temp[i]表示的是组成的长度为i + 1的子序列中的list的最小的数,注意结合二分查找
//最优解
public class Solution {
public int lengthOfLIS(int[] nums) {
int[] tails = new int[nums.length];
int size = 0;
for (int x : nums) {
int i = 0, j = size;
while (i != j) {
int m = i + (j - i) >> 1;
if (tails[m] < x)
i = m + 1;
else
j = m;
}
tails[i] = x;
if (i == size) ++size;
}
return size;
}
}
48. Rotate Image
思路:1.第一个计算处于第几层,第二个计算first- last,这个是要分两层进行的,还要计算偏移量 从 first 到last,last - first = offset, 一般4 *4可以对照着写出来
2. 如果是顺势针, it will be swap(matrix[i][j], matrix[j][i]), (swap(matrix[i][j], matrix[i][matrix.length-1-j])
75. Sort Colors
3种颜色, 0 ,1 ,2进行桶排序
思路:1.用3个数分别进行缓存,桶排序的基础
2.从左到右, 两个num0与num2进行下标的交换存储
116. Populating Next Right Pointers in Each Node
每个二叉树结点多了一个next结点
思路:1。给一个二叉树,对同一级别的,左边的next为右边结点,广搜的改变,增加设计一个包装类,结点为node跟level。这个是很通用的一个方法,不对树有更多的要求
2. 从上到依次进行操作,先将本节点的left 的下一个调整为 right ,然后将本结点的right的下一个调整为 本节点下一个的left, 本节点等于本节点的下一个。为空则进入左子树,对下一层进行操作。对树形有一点要求。这个速度就快了。
289. Game of Life
康威生命游戏,程序实现规则,需要注意的是不可以直接对原数组进行操作,需要将原数组进行复制。
这个很有微软的hihocode的风格,都是基于规则的实现。
162. Find Peak Element
找到峰值点,峰值点的数比左右两个数都大。
最优解: 二分法处理,根据峰的两侧变化趋势相同,可以唯一确定
二分法也是个大法宝,跟递归类似
public class Solution {
public int findPeakElement(int[] nums) {
int low = 0;
int high = nums.length - 1;
while (low < high) {
int mid1 = low + ((high - low) >> 1);
int mid2 = mid1 + 1;
if (nums[mid1] < nums[mid2]) {
low = mid2;
} else {
high = mid1;
}
}
return low;
}
}
11. Container With Most Water
给定一个数组,从左往右是表示y,也就是高度,下标为x也就是宽度的位置
最优解: 从左右两边开始迭代,发现高度高于两者的,就进行更新比较,所以速度会快很多
395. Longest Substring with At Least K Repeating Characters
此题一刷无思路,典型的分治法解决的问题. 在子问题上,先从开始到结束统计出各个字母的个数,然后去得26个子母中出现但是出现次数不到k的,进行左右子串的分解,不包括被分解的点。进行递归,返回最大的值。
public class Solution {
public int longestSubstring(String s, int k) {
char[] str = s.toCharArray();
return helper(str, 0, str.length, k);
}
private int helper(char[] str, int start, int end, int k){
if (end - start < k) {
return 0;
}
int[] count = new int[26];
for (int i = start; i < end; i++) {
int ind = str[i] - 'a';
count[ind]++;
}
for (int x = 0; x < 26; x++) {
if (count[x] < k && count[x] > 0) {
for (int y = start; y < end; y++) {
if (str[y] == x + 'a') {
int left = helper(str, start, y, k);
int right = helper(str, y + 1, end, k);
return Math.max(left, right);
}
}
}
}
return end - start;
}
}