//二叉树搜索
public void binarySearch(TreeNode root) {
//返回条件
//return ;
/*
这里写前序遍历的操作
*/
binarySearch(root.left);
/*
这里写中序遍历的操作
*/
binarySearch(root.right);
/*
这里写后序遍历的操作
*/
//返回
return;
}
//n叉树搜索
public void nSearch(NNodeTree root) {
//返回条件
//return ;
/*
这里写前序遍历的操作
*/
for (int i = 0; i < root.children.length; i++) {
nSearch(root.children[i]);
/*
这里写中序遍历的操作
*/
}
/*
这里写后序遍历的操作
*/
//返回
return;
}
//回溯算法
public List<List<Integer>> res = new ArrayList<>();
public void backTrack(int[] nums, LinkedList<Integer> track) {
if (track.size() == nums.length) {
res.add(track);
return;
}
for (int i = 0; i < nums.length; i++) {
if (track.contains(i))
continue;
track.add(nums[i]);
backTrack(nums, track);
track.removeLast();
}
}
动态规划问题主要考的是一种看问题的思考方式
//动态规划
public void dynamicProgramming(int[] num, int target) {
int[] dp = new int[num.length];
for (int i = 0; i < num.length; i++) {
// for (int j = 0; j < ; j++) {
//状态转移方程
//条件判断
// dp[i]=
// }
}
}
//广度优先搜索
public void bfs(TreeNode root, TreeNode target) {
if (root == null) {
return;
}
//队列
Queue<TreeNode> queue = new LinkedList<>();
//哈希表记录已经访问过的节点
//如果是二叉树就不需要了
Set<TreeNode> isVisited = new HashSet<>();
//先初始化一下
queue.offer(root);
isVisited.add(root);
while (!queue.isEmpty()) {
TreeNode cur = queue.poll();
if (cur == target) return;
queue.add(root.left);
queue.add(root.right);
//如果是多叉树
// for (int i = 0; i < root.children.lenth; i++) {
// if(!isVisited.contains(root[i]){
// queue.offer(root[i]);
// isVisited.add(root[i]);
// }
// }
//步数++
}
//返回数值
return;
}
//双指针1:判断链表的环
boolean hasCycle(ListNode head) {
ListNode fast, slow;
fast = slow = head;
while (head != null && head.next != null) {
fast = fast.next.next;
slow = slow.next;
if (slow == fast)
return true;
}
return false;
}
//双指针2:判断链表的环的交点
ListNode detectCycle(ListNode head) {
ListNode fast, slow;
fast = slow = head;
while (head != null && head.next != null) {
fast = fast.next.next;
slow = slow.next;
if (slow == fast)
break;
}
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
//双指针3:左右指针
//典型的是二分查找
int binarySearch(int[] nums, int target){
if(nums.length==0)return -1;
int left =0,right =nums.length-1;
while (left<=right){
int mid = left+(right-left)>>1;
if (nums[mid] == target) {
return mid;
}else if(nums[mid]<target){
left=mid+1;
}else if(nums[mid]>target){
right=mid-1;
}
}
return -1;
}
//滑动窗口
void slidingWindow(String s ,String t){
Map<Character,Integer> map = new HashMap<>();
Map<Character,Integer> need = new HashMap<>();
for (char c : t.toCharArray()) {
need.put(c,need.getOrDefault(c,0)+1);
}
int left=0,right = 0;
char[] chars = s.toCharArray();
while (right != s.length()) {
//处理逻辑
while (true/*这里写缩小的条件*/){
//处理逻辑
}
}
return;
}
下面是我刚开始按照顺序刷算法的一些题目。刷了一周感觉效果不是特别好,所以就按照例题刷。后来学了一些模板再去看问题,真的会很不一样!
技巧:使用HashMap将集合的数保存
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> Sites = new HashMap<Integer, Integer>();
for (int i = 0; i < nums.length; i++) {
int sum = target - nums[i];
if (Sites.containsKey(sum)) {
return new int[]{i, Sites.get(sum)};
}
Sites.put(nums[i], i);
}
throw new IllegalArgumentException("No two sum solution");
}
202121/9/7
这题解法很常见。因为两个两位数相加,进位位只可能是0或者1,在每个节点创建时,我们只需要加上前一位数的进位位和本位之和。注释已经写的很详细啦~
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode headNode = new ListNode(0);//头结点
ListNode tempNode = headNode;//临时用来操作的节点
int carry = 0;//保存进位
//如果遍历两个链表时,值都是空的话,才退出,否则继续执行操作
while (l1 != null || l2!= null) {
//由于两个链表的长度不同,所以我们得定义变量来进行算数
//因为while循环会导致一个空指针
//如果为空指针,加数或者被加数为0即可
int x = (l1 != null) ? l1.val : 0;
int y = (l2 != null) ? l2.val : 0;
//这里算出加上前一位数进位位的和
int sum = carry + x + y;
//算出这一位的进位位
carry = sum / 10;
//sum % 10 保证在10以内
tempNode.next = new ListNode(sum % 10);
//新链表的指针移动
tempNode = tempNode.next;
//判定是否为空,空就不移动
//这里如果两个链表不一样长,就会出现空值
if (l1 != null) l1 = l1.next;
if (l2 != null) l2 = l2.next;
}
//最后如果有进位位的话,记得加载尾节点
if (carry > 0) {
tempNode.next = new ListNode(carry);
}
return headNode.next;
}
}
我们使用List优化
public String convert(String s, int numRows) {
if (numRows == 1) return s;
List<StringBuilder> rows = new ArrayList<>();
for (int i = 0; i < Math.min(numRows, s.length()); i++)
rows.add(new StringBuilder());
int curRow = 0;
boolean goingDown = false;
for (char c : s.toCharArray()) {
rows.get(curRow).append(c);
if (curRow == 0 || curRow == numRows - 1) goingDown = !goingDown; //遍历到两端,改变方向
curRow += goingDown ? 1 : -1;
}
StringBuilder ret = new StringBuilder();
for (StringBuilder row : rows) ret.append(row);
return ret.toString();
}
(https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/)
2021/9/8
这里最先想到的是暴力枚举所有的可能性,不过这肯定不是最好的算法。
之后想到了跟第一题一样,用Map。Key是字符,head记录头节点到哪了,tail记录尾节点,Value是给定的下标,然后判断是否在之前添加过,如果存在,保存一下这个Key的Value数值,相应的就是head,然后添加后面重复的字符。最后输出的就是head和tail的差值。
public static int lengthOfLongestSubstring(String s) {
int n = s.length(), ans = 0;
Map<Character, Integer> map = new HashMap<>();
for (int j = 0, i = 0; j < n; j++) {
if (map.containsKey(s.charAt(j))) {
i = Math.max(map.get(s.charAt(j)), i);
}
ans = Math.max(ans, j - i + 1);
map.put(s.charAt(j), j + 1);//下标 + 1 代表 i 要移动的下个位置
}
return ans;
}
这三天要打数模,先不更三天哈。
https://leetcode-cn.com/problems/median-of-two-sorted-arrays/
2021/9/14
昨天写了代码太过混乱,还没解出来,今天补上。
我们合并两个数组存放在一个新的数组,最后直接取数组的中间数。
int[] result;
int anum = nums1.length;
int bnum = nums2.length;
result = new int[anum + bnum];
if (anum == 0) {
if (bnum % 2 == 0) {
return (nums2[bnum / 2 - 1] + nums2[bnum / 2]) / 2.0;
} else {
return nums2[bnum / 2];
}
}
if (bnum == 0) {
if (anum % 2 == 0) {
return (nums1[anum / 2 - 1] + nums1[anum / 2]) / 2.0;
} else {
return nums1[anum / 2];
}
}
//用来计信数组里的数
int count = 0;
int i = 0, j = 0;
//新的数组还没到达两个数组之和
while (count != (anum + bnum)) {
if (i == anum) {
//第一个数组已经遍历完了,但是还能继续遍历第二个数组
while (j != bnum) {
result[count++] = nums2[j++];
}
break;
}
if (j == bnum) {
//第二个数组已经遍历完了,但是还能继续遍历第一个数组
while (i != anum) {
result[count++] = nums1[i++];
}
break;
}
if (nums1[i] < nums2[j]) {
//数组二大
result[count++] = nums1[i++];
} else {
//数组一大
//这里要是两个数一样,同样只添加一个数,这里是个坑
result[count++] = nums2[j++];
}
}
//判断结果数组是不是双数
if (count % 2 == 0) {
//双数情况需要中间两个数求平均
return (result[count / 2 - 1] + result[count / 2]) / 2.0;
} else {
//单数直接返回一半
return result[count / 2];
}
9/15
https://leetcode-cn.com/problems/longest-palindromic-substring/submissions/
暴力解法,遍历每一次字符,每次遍历都核对一下是否是回文字符。但是时间复杂度O(n`3)太大,并没有通过。
public static String longestPalindrome(String s) {
if (s.length() == 1) {
return s;
}
String targetS=String.valueOf(s.charAt(0));
boolean findIt=false ;
int j =0;
//只需要长度-1次
for (int i = 0; i < s.length(); i++) {
for (j = i+1; j <= s.length() ; j++) {
String tempS;
tempS = s.substring(i,j);
findIt = checkPalindrome(tempS);
if (findIt ==true){
if (targetS.length()<tempS.length()){
targetS=tempS;
}
}
}
}
return targetS;
return String.valueOf(s.charAt(0));
}
private static boolean checkPalindrome(String rome) {
System.out.println("rome====>"+rome);
int tail = rome.length()-1;
int start =0;
if (start == tail) {
return false;
}
for (int i = start; i < rome.length(); i++) {
if (i >= tail){
return true;
}
if (rome.charAt(i)!= rome.charAt(tail)) {
return false;
}
tail--;
}
return true;
}
方法二是寻找最长公共子串的方法:
https://blog.csdn.net/u010397369/article/details/38979077
先暂时写到这啦。
9/16
https://leetcode-cn.com/problems/zigzag-conversion/
public String convert(String s, int numRows) {
int hor = 1, ver = 0;
if (s.length() == 1 || numRows == 1) {
return s;
}
int verNum = ((s.length() - numRows) / (numRows - 1)) + 1;
if (numRows + (verNum - 1) * (numRows - 1) != s.length()) {
verNum++;
}
char[][] arr = new char[numRows][verNum];
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < verNum; j++) {
arr[i][j] = '1';
}
}
arr[0][0] = s.charAt(0);
boolean isUp = false;
int i = 1;
while (i < s.length()) {
arr[hor][ver] = s.charAt(i);
if (i == s.length() - 1) {
break;
}
if (hor == numRows - 1) {
//说明要向上走
ver++;
// arr[hor][ver]='1';
hor--;
i++;
arr[hor][ver] = s.charAt(i);
isUp = true;
}
if (i == s.length() - 1) {
break;
}
if (hor == 0) {
//说明要向下走
ver++;
// arr[hor][ver]='1';
hor++;
i++;
arr[hor][ver] = s.charAt(i);
isUp = hor == numRows - 1;
}
if (isUp) {
//向上走
hor--;
i++;
} else {
hor++;
i++;
}
}
String result = new String();
for (int m = 0; m < numRows; m++) {
for (int j = 0; j < verNum; j++) {
if (arr[m][j] != '1') {
result += arr[m][j];
}
}
}
return result;
}
9/17
https://leetcode-cn.com/problems/reverse-integer/
这道题比较简单
public int reverse(int x) {
int result = 0;
while (x != 0) {
if (result>Integer.MAX_VALUE/10) return 0;
if (result<Integer.MIN_VALUE/10) return 0;
result*=10;
result += x % 10;
x /= 10;
}
return result;
}
https://leetcode-cn.com/problems/string-to-integer-atoi/
感觉这题主要是考对于一些条件的 判断。
int sign = 1;
int result = 0, temp = 0;
boolean hasSign = false; //代表是否开始转换数字
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '-' && !hasSign) {
sign = -1;
hasSign = true;
continue;
}
if (s.charAt(i) == '+' && !hasSign) {
sign = 1;
hasSign = true;
continue;
}
if (s.charAt(i) == ' ' && !hasSign) {
continue;
}
if (s.charAt(i) >= '0' && s.charAt(i) <= '9') {
hasSign = true;
temp = s.charAt(i) - '0';
//这里题目有个坑
//不判断>7根本过不了
if (result * sign > Integer.MAX_VALUE / 10 || (result * sign == Integer.MAX_VALUE / 10 && temp * sign > 7))
return 2147483647;
if (result * sign < Integer.MIN_VALUE / 10 || (result * sign == Integer.MIN_VALUE / 10 && temp * sign < -8))
return -2147483648;
result = result * 10 + temp;
} else {
return result * sign;
}
}
return result * sign;
https://leetcode-cn.com/problems/palindrome-number/
9/22
这题比较简单,直接比较数字的后半段和前半段是否一样
public static boolean isPalindrome(int x) {
//提前排除掉一些结果
if (x < 0 || (x % 10 == 0 && x != 0)) {
return false;
}
int reverseNum = 0;
int len = (int) (Math.log(x) / Math.log(10) + 1);
for (int i = 0; i < len / 2; i++) {
//这里跟前面的题一样,需要判断是否大于2147483647 或小于-2147483648
if(reverseNum>Integer.MAX_VALUE/10||reverseNum<Integer.MIN_VALUE/10) return false;
reverseNum=reverseNum*10+x%10;
System.out.println(reverseNum);
x/=10;
}
//位数为偶的情况
if(len%2==0&&x==reverseNum) return true;
if (len%2!=0&&x/10==reverseNum) return true;
return false;
}
在这里我们可以看到,我们需要算出x的位数,能不能再优化一下呢?
public boolean isPalindrome(int x) {
if (x < 0 || (x % 10 == 0 && x != 0)) {
return false;
}
int reverseNum = 0;
//这里我们直接对x进行操作只需要比较x和reverseNum的大小即可
while (x > reverseNum) {
if (reverseNum > Integer.MAX_VALUE / 10 || reverseNum < Integer.MIN_VALUE / 10) return false;
reverseNum=reverseNum*10+x%10;
x/=10;
}
//x为偶数位的情况||x为奇数位的情况
return reverseNum==x||reverseNum/10==x;
}
https://leetcode-cn.com/problems/regular-expression-matching/
9/23
这道题刚开始理解错题意了,没做出来。刚开始想的是找到 p 中的跟 s 相同的子串也返回true。结果看来别人的题解才发现只能是在. 和 *
左右下,s 和 p 相同才返回 true。
利用递归的方式:先不加*
的写法写出来
public static boolean isMatch(String s, String p) {
//因为我们会对s和p删除操作,并且p一定需要比s长,所以出口就是判断p是否为空
//p空了s还有字符说明没有实现一一对应的关系,返回false
//p和s同时空了,就说明匹配了
if (p.isEmpty()) return s.isEmpty();
//这里需要判断s是否为空,空了的话下一条return语句就不会继续substring
//后面判断字符是否相同或者p出现了”.“
boolean firstCheck = !s.isEmpty() && (p.charAt(0) == '.' || s.charAt(0) == p.charAt(0));
//返回上面的判断以及继续寻找后面的字符是否相等
return firstCheck && isMatch(s.substring(1), p.substring(1));
}
没有加*
的模式很容易,再来看看加了这个条件的
public static boolean isMatch(String s, String p) {
//前面都一样
if (p.isEmpty()) return s.isEmpty();
boolean first_match = (!s.isEmpty() &&
(p.charAt(0) == s.charAt(0) || p.charAt(0) == '.'));
//只有长度大于 2 的时候,才考虑 *
//第二个字符是*
if (p.length() >= 2 && p.charAt(1) == '*') {
//两种情况
//p 直接跳过两个字符。表示 * 前边的字符出现 0 次
//p 不变,例如 s = aa ,p = a*,第一个 a 匹配,然后 s的第二个 a 接着和 p 的第一个 a 进行匹配。表示 * 用前一个字符替代。
//这里优点耗费时间,两种情况都遍历
return (isMatch(s, p.substring(2)) ||
(first_match && isMatch(s.substring(1), p)));
} else {
//这里和之前一样
return first_match && isMatch(s.substring(1), p.substring(1));
}
}
https://leetcode-cn.com/problems/roman-to-integer/
9/24
这题比较简单,想到的第一个方法就是将原有的数存在哈希表中,Key 是字符,Value 是对应的 10 进制数,遍历寻找。
public int romanToInt(String s) {
Map<Character, Integer> map = new HashMap<>();
map.put('I', 1);
map.put('V', 5);
map.put('X', 10);
map.put('L', 50);
map.put('C', 100);
map.put('D', 500);
map.put('M', 1000);
int result = 0;
for (int i = 0; i < s.length(); i++) {
int temp = map.get(s.charAt(i));
if (i < s.length() - 1) {
//说明有可能出现减法
int tempNext = map.get(s.charAt(i + 1));
if (tempNext > temp) {
result += (tempNext - temp);
//跳过这两个字符,不再继续执行
i++;
continue;
}
}
//不存在该字符比下一个字符大的情况、最后一位数的处理方式
result += temp;
}
return result;
}
我们呢还能不用哈希表来做:
public static int romanToInt(String s) {
int result =0;
int i =0;
//判断是否存在减法的数,存在就将其加入结果,并且删去这两个字符
if((i=s.indexOf("IV"))!=-1){
result+=4;
s= s.substring(0, i)+s.substring(i+2);
}
if((i=s.indexOf("IX"))!=-1){
result+=9;
s= s.substring(0, i)+s.substring(i+2);
}
if((i=s.indexOf("XL"))!=-1){
result+=40;
s= s.substring(0, i)+s.substring(i+2);
}
if((i=s.indexOf("XC"))!=-1){
result+=90;
s= s.substring(0, i)+s.substring(i+2);
}
if((i=s.indexOf("CD"))!=-1){
result+=400;
s= s.substring(0, i)+s.substring(i+2);
}
if((i=s.indexOf("CM"))!=-1){
result+=900;
s= s.substring(0, i)+s.substring(i+2);
}
//最后再遍历一下,按照正常输出就可以了;
for (int i1 = 0; i1 < s.length(); i1++) {
switch (s.charAt(i1)){
case 'I':
result+=1;
break;
case 'V':
result+=5;
break;
case 'X':
result+=10;
break;
case 'L':
result+=50;
break;
case 'C':
result+=100;
break;
case 'D':
result+=500;
break;
case 'M':
result+=1000;
break;
}
}
return result;
}
可以看到,我们使用s.subStirng
的时候需要时间,如何不用它呢
public int romanToInt(String s) {
int sum=0;
//直接减去少的值(注意这里需要减两倍差值),我们后面遍历就可以直接加上每个罗马数字应该有的数值了
if(s.indexOf("IV")!=-1){sum-=2;}
if(s.indexOf("IX")!=-1){sum-=2;}
if(s.indexOf("XL")!=-1){sum-=20;}
if(s.indexOf("XC")!=-1){sum-=20;}
if(s.indexOf("CD")!=-1){sum-=200;}
if(s.indexOf("CM")!=-1){sum-=200;}
char c[]=s.toCharArray();
int count=0;
for(;count<=s.length()-1;count++){
if(c[count]=='M') sum+=1000;
if(c[count]=='D') sum+=500;
if(c[count]=='C') sum+=100;
if(c[count]=='L') sum+=50;
if(c[count]=='X') sum+=10;
if(c[count]=='V') sum+=5;
if(c[count]=='I') sum+=1;
}
return sum;
}
这题比较简单,只需要每次算出最大值,保存一下即可。
看可以优化的点就是那两个while,如果小的那一个数比之前最短的还小,可直接跳过
public static int maxArea(int[] height) {
int i = 0, j = height.length - 1,max = 0;
while(i < j) {
int h = Math.min(height[i], height[j]);
max = Math.max(max, (j - i) * h);
while (height[i] <= h && i < j)
i++;
while (height[j] <= h && i < j)
j--;
}
return max;
}
9/26
https://leetcode-cn.com/problems/integer-to-roman/
思路简单,直接把罗马数和我们的数对应写出来,挨个比对,对完就减小一下num。
public static String intToRoman(int num){
int []values = new int[]{1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
String []symble= new String[]{"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
StringBuilder res=new StringBuilder("");
int i=0;
while (num > 0) {
while (values[i] > num) {
i++;
}
num-=values[i];
res.append(symble[i]);
}
return res.toString();
}
https://leetcode-cn.com/problems/3sum/
这题可以用到双指针。
解法一:先将数据排序,固定一个指针,另外两个在头和尾部,符合条件就载入容器。
这题的难点在于需要去重。
public List<List<Integer>> threeSum(int[] nums) {
nums = sort(nums);
if (nums == null || nums.length == 0) {
return new ArrayList<>();
}
List<Integer> innerList;
List<List<Integer>> outerList = new ArrayList<>();
int j = 1;
while (j < nums.length - 1) {
int start = 0;
int end = nums.length - 1;
if (j > 1 && nums[j] == nums[j - 1]) {
start = j - 1;
}
while (start < j && end > j) {
if (start > 0 && nums[start - 1] == nums[start]) {
//相同的情况
start++;
continue;
}
if (end < nums.length - 1 && nums[end + 1] == nums[start]) {
end--;
continue;
}
int and = nums[start] + nums[end] + nums[j];
if (and == 0) {
innerList = new ArrayList<>();
innerList.add(nums[start]);
innerList.add(nums[end]);
innerList.add(nums[j]);
outerList.add(innerList);
start++;
end--;
} else if (and < 0) {
start++;
} else {
end--;
}
}
j++;
}
return outerList;
}
private static int [] sort(int[] nums) {
int temp =0;
for (int i = 0; i < nums.length-1; i++) {
for (int j = 0; j <nums.length-i-1 ; j++) {
if(nums[j]>nums[j+1]){
temp=nums[j];
nums[j]=nums[j+1];
nums[j+1]=temp;
}
}
}
return nums;
}
解法二,力扣时间超过99%的解法。先桶排序,然后双指针,利用这两个指针判断第三个值存不存在,存在就加入列表,当然这里用到了桶,直接判断就行。
import java.util.*;
class Solution {
public static List<List<Integer>> threeSum(int[] nums) {
if (nums.length < 3) return List.of();
int min = nums[0], max = min, size = 0;
for (int num : nums)
if (num < min) min = num;
else if (num > max) max = num;
if (min > 0 || max < 0) return List.of();
int[] sorted = new int[max - min + 1];
for (int num : nums) sorted[num - min]++;
for (int i = min; i <= max; i++)
if (sorted[i - min] > 0) nums[size++] = i;
List<List<Integer>> res = new ArrayList<>();
for (int i = 0, ni; (ni = nums[i]) < 0; i++) {
for (int j = size - 1, nj, t; (t = -ni - (nj = nums[j])) <= nj; j--) {
if (t >= ni)
if (t == ni) {
if (sorted[ni - min] > 1) res.add(new IntList(ni, t, nj));
} else if (t == nj) {
if (sorted[nj - min] > 1) res.add(new IntList(ni, t, nj));
} else if (sorted[t - min] > 0) res.add(new IntList(ni, t, nj));
}
}
if (sorted[-min] >= 3) res.add(new IntList(0, 0, 0));
return res;
}
static class IntList extends AbstractList<Integer> {
private int[] values;
public IntList(int... values) {
this.values = values;
}
public Integer get(int index) {
return values[index];
}
public int size() {
return values.length;
}
}
}
https://leetcode-cn.com/problems/3sum-closest/submissions/
这一题和上一题略微有点不同,要找到最接近的target的三数和。
这里只需要把三数和保存一下,然后对比target。
public static int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int deff = Integer.MAX_VALUE;
int result =0;
for (int head = 0; head < nums.length - 2; head++) {
if (head > 0 && nums[head] == nums[head - 1]) {
continue;
}
for (int j = head + 1, tail = nums.length - 1; j < tail; ) {
int sum = nums[head] + nums[tail] + nums[j];
if (Math.abs(sum - target) < deff) {
result=sum;
deff = Math.abs(sum - target);
}
if (sum == target) {
return result;
} else if (sum > target) {
tail--;
} else {
j++;
}
}
}
return result;
}
https://leetcode-cn.com/problems/4sum/
和三数相加、两数相加没什么大的区别,就多加了一层的for(多加一个指针)
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> quadruplets = new ArrayList<List<Integer>>();
if (nums == null || nums.length < 4) {
return quadruplets;
}
Arrays.sort(nums);
int length = nums.length;
for (int i = 0; i < length - 3; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
if (nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
break;
}
if (nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
for (int j = i + 1; j < length - 2; j++) {
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
if (nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {
break;
}
if (nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
int left = j + 1, right = length - 1;
while (left < right) {
int sum = nums[i] + nums[j] + nums[left] + nums[right];
if (sum == target) {
quadruplets.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
while (left < right && nums[left] == nums[left + 1]) {
left++;
}
left++;
while (left < right && nums[right] == nums[right - 1]) {
right--;
}
right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
}
}
return quadruplets;
}
https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/
代码很简单,就是要注意一下细节方面
public static ListNode removeNthFromEnd(ListNode head, int n) {
ListNode temp= new ListNode(0,head);
int length = 0;
while (temp.next != null) {
length++;
temp=temp.next;
}
if(n==1&&length==1)return null;
temp= new ListNode(0,head);
ListNode temp2=temp;
length=length-n;
while (length > 1) {
temp=temp.next;
length--;
}
temp.next=temp.next.next;
return temp2.next;
}
https://leetcode-cn.com/problems/merge-two-sorted-lists/
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1==null){
return l2;
}
if(l2==null){
return l1;
}
if(l1.val<l2.val){
l1.next=mergeTwoLists(l1.next,l2);
return l1;
}else {
l2.next=mergeTwoLists(l1,l2.next);
return l2;
}
}
https://leetcode-cn.com/problems/merge-k-sorted-lists/
public static ListNode mergeKLists(ListNode []lists) {
if(lists.length==0){
return null;
}
if(lists.length==1){
return lists[0];
}
if(lists.length==2){
return mergeTwoLists(lists[0],lists[1]);
}
ListNode []left = new ListNode[lists.length/2];
for (int i = 0; i < left.length; i++) {
left[i]=lists[i];
}
ListNode []right = new ListNode[lists.length-lists.length/2];
for (int i = 0; i < left.length; i++) {
right[i]=lists[i+ left.length];
}
return mergeTwoLists(mergeKLists(left),mergeKLists(right));
}
public static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1==null){
return l2;
}
if(l2==null){
return l1;
}
if(l1.val<l2.val){
l1.next=mergeTwoLists(l1.next,l2);
return l1;
}else {
l2.next=mergeTwoLists(l1,l2.next);
return l2;
}
}
https://leetcode-cn.com/problems/swap-nodes-in-pairs/
这里普通方法的话是直接两个两个交换,另外一种优美的方法是递归。
当然,由于列表的值是顺序排序的,而且是自然数,所以可以直接更改val也行。
//递归方式
public ListNode swapPairs(ListNode head) {
if(head==null||head.next==null)return head;
ListNode next = head.next;
head.next=swapPairs(next.next);
next.next = head;
return next;
}
五行代码解决~
public ListNode reverseKGroup(ListNode head, int k) {
if(head==null)return head;
ListNode cur = head;
ListNode prev = null;
ListNode next=null;
int count = 0;
int num=0;
while (num < k && cur != null) {
cur = cur.next;
num++;
}
if (num>=k){
//反转
cur = head;
while (cur!=null&&count<k){
next=cur.next;
cur.next =prev;
prev=cur;
cur=next;
count++;
}
if(next!=null){
head.next=reverseKGroup(next,k);
}
return prev;
}else {
//数量不够不反转
return head;
}
}
https://leetcode-cn.com/problems/rotate-list/
public ListNode rotateRight(ListNode head, int k) {
if(head == null || head.next == null) return head;
if(k == 0) return head;
ListNode tail = head, newtail = head;
ListNode newhead;
int n = 1;
// 原来的尾结点指向原来的头结点,形成环
while(tail.next != null){
tail = tail.next;
n++;
}
tail.next = head;
// 找到断开环的位置
for(int i = 0; i < (n - k % n - 1); i++){
newtail = newtail.next;
}
// 新的头结点指向断开环的位置
newhead = newtail.next;
newtail.next = null;
return newhead;
}
https://leetcode-cn.com/problems/valid-parentheses/
public boolean isValid(String s) {
Stack<Character> stack = new Stack<Character>();
for (char c : s.toCharArray()) {
if(c=='{')stack.push('}');
else if(c=='[')stack.push(']');
else if(c=='(')stack.push(')');
else if(stack.isEmpty()||c!=stack.pop()) return false;
}
return stack.isEmpty();
}
https://leetcode-cn.com/problems/trapping-rain-water/
public static int trap(int[] height) {
Stack<Integer> stack = new Stack<>();
int result =0;
for (int i = 0; i < height.length; i++) {
while(!stack.isEmpty()&&height[i]>height[stack.peek()]){
int top = stack.pop();
if (stack.isEmpty()) {
break;
}
int left = stack.peek();
int wide =i-left-1;
int high = Math.min(height[left],height[i])-height[top];
result+=wide*high;
}
stack.push(i);
}
return result;
}
public int trap(int[] height) {
int all = 0;
int left = 0;
int right = height.length - 1;
int leftMax = height[left];
int rightMax = height[right];
while(left <= right){
if(leftMax <= rightMax){
leftMax = Math.max(leftMax, height[left]);
all += leftMax - height[left++];
}else{
rightMax = Math.max(rightMax, height[right]);
all += rightMax - height[right--];
}
}
return all;
}
https://leetcode-cn.com/problems/simplify-path/
//利用split函数讲路径提取出来,然后利用栈保存数据,最后加上题目的一些条件即可
public String simplifyPath(String path) {
String[] split = path.trim().split("/");
Stack<String> stack = new Stack<>();
for (int i = 0; i < split.length; i++) {
if(split[i].equals("..")){
if(!stack.isEmpty()){
//返回前一个
stack.pop();
}
}else {
if(!split[i].equals(".")&&!split[i].equals("")){
stack.push(split[i]);
}
}
}
if (stack.isEmpty()) {
return "/";
}else{
String res = "";
for (String s : stack) {
res+="/"+s;
}
return res;
}
}
https://leetcode-cn.com/problems/largest-rectangle-in-histogram/
这题比较好的思想很重要。如果height[0~i]
里放的全是递增的,height[i+1]
比height[i]
小 ,那我们怎么处理?是不是直接从i
开始一直往前找最大的即可。
public int largestRectangleArea(int[] heights) {
int[] tmp = new int[heights.length + 2];
System.arraycopy(heights, 0, tmp, 1, heights.length);
Deque<Integer> stack = new ArrayDeque<>();
int area = 0;
for (int i = 0; i < tmp.length; i++) {
while (!stack.isEmpty()&&tmp[i]<tmp[stack.peek()]){
int h =tmp[stack.pop()];
area = Math.max(area,(i-stack.peek()-1)*h);
}
stack.push(i);
}
return area;
}
https://leetcode-cn.com/problems/binary-tree-inorder-traversal/
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> inner = new ArrayList<>();
if (root == null) {
return inner;
}
inner.addAll(inorderTraversal(root.left));
inner.add(root.val);
inner.addAll(inorderTraversal(root.right));
return inner;
}
https://leetcode-cn.com/problems/unique-binary-search-trees-ii/
public List<TreeNode> generateTrees(int n) {
return myGenerateTrees(1,n);
}
private List<TreeNode> myGenerateTrees(int start, int end) {
List<TreeNode> res= new ArrayList<>();
if(start>end){
res.add(null);
return res;
}
for (int i = start; i <= end; i++) {
List<TreeNode> leftTree = myGenerateTrees(start, i - 1);
List<TreeNode> rightTree = myGenerateTrees(i+1,end);
for (TreeNode left : leftTree) {
for (TreeNode right : rightTree) {
TreeNode curTree = new TreeNode(i);
curTree.left=left;
curTree.right=right;
res.add(curTree);
}
}
}
return res;
}
https://leetcode-cn.com/problems/unique-binary-search-trees/
//不需要考虑是不是搜索树
public int numTrees(int n) {
int[] dp=new int[n+1];
dp[0]=1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
dp[i] += dp[j - 1] * dp[i - j];
}
}
return dp[n];
}
https://leetcode-cn.com/problems/validate-binary-search-tree/
public boolean isValidBST(TreeNode root) {
return mIsValidBST(root,Long.MIN_VALUE,Long.MAX_VALUE);
}
private boolean mIsValidBST(TreeNode root, long minValue, long maxValue) {
if(root==null)return true;
if(root.val<=minValue||root.val>=maxValue)return false;
return mIsValidBST(root.left,minValue,root.val)&&mIsValidBST(root.right,root.val,maxValue);
}
https://leetcode-cn.com/problems/recover-binary-search-tree/
public void recoverTree(TreeNode root) {
Deque<TreeNode> stack = new ArrayDeque<TreeNode>();
TreeNode x = null, y = null, pred = null;
while (!stack.isEmpty() || root != null) {
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
if (pred != null && root.val < pred.val) {
y = root;
if (x == null) {
x = pred;
} else {
break;
}
}
pred = root;
root = root.right;
}
swap(x, y);
}
public void swap(TreeNode x, TreeNode y) {
int tmp = x.val;
x.val = y.val;
y.val = tmp;
}
//不用栈的方式
public void recoverTree(TreeNode root) {
if (root==null||root.left==null&&root.right==null)return;
dfs(root);
int temp = n1.val;
n1.val=n2.val;
n2.val=temp;
return;
}
private void dfs(TreeNode cur){
if(cur==null)return;
dfs(cur.left);
if (pre != null && pre.val > cur.val) {
if (n1 == null) n1 = pre;
n2 = cur;
}
pre=cur;
dfs(cur.right);
}
https://leetcode-cn.com/problems/same-tree/
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p==null&&q==null)return true;
if(p==null||q==null) return false;
return p.val==q.val&&isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);
}
https://leetcode-cn.com/problems/symmetric-tree/
public boolean isSymmetric(A92BinaryTreeInorderTraversal.TreeNode root) {
return doSomething(root.left,root.right);
}
private boolean doSomething(A92BinaryTreeInorderTraversal.TreeNode left, A92BinaryTreeInorderTraversal.TreeNode right) {
if(left==null&&right==null)return true;
if(left==null||right==null)return false;
return left.val==right.val&&doSomething(left.left,right.right)&&doSomething(left.right,right.left);
}
https://leetcode-cn.com/problems/binary-tree-level-order-traversal/
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> lists= new ArrayList<>(new ArrayList<>());
if(root==null)return lists;
return myLevleOrder(root,1,lists);
}
private List<List<Integer>> myLevleOrder(TreeNode root, int i,List<List<Integer>> lists) {
if(root==null)return lists;
if (lists.size()<i) {
lists.add(new ArrayList<>());
}
lists.get(i).add(root.val);
myLevleOrder(root.left,i+1,lists);
myLevleOrder(root.right,i+1,lists);
return lists;
}
https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal/
代码很简单,就是上面一题的原本方法,获得完链表之后就判断是否需要翻转就行。
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> lists = new ArrayList<>();
mZigzagLevelOrder(lists, 1, root);
for (int i = 0; i < lists.size(); i++) {
if (i % 2 != 0)
Collections.reverse(lists.get(i));
}
return lists;
}
private void mZigzagLevelOrder(List<List<Integer>> lists, int i, TreeNode root) {
if (root == null) return;
if (lists.size() < i) lists.add(new ArrayList<>());
lists.get(i-1).add(root.val);
mZigzagLevelOrder(lists, i + 1, root.left);
mZigzagLevelOrder(lists, i + 1, root.right);
return;
}
https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/
public int maxDepth(TreeNode root) {
if(root==null)return 0;
return Math.max(maxDepth(root.left),maxDepth(root.right))+1;
}
https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
千言万语汇于一图中,主要是需要找到规律。
public TreeNode buildTree(int[] preorder, int[] inorder) {
Map<Integer,Integer> map = new HashMap<>();
for (int i = 0; i < preorder.length; i++) {
map.put(inorder[i],i);
}
return buildTree(preorder,map,0,preorder.length-1,0,inorder.length-1);
}
private TreeNode buildTree(int[] preorder, Map<Integer, Integer> pMap, int preLeft, int preRight, int inLeft, int inRight) {
if(preLeft>preRight||inLeft>inRight)return null;
TreeNode root = new TreeNode(preorder[preLeft]);
int rootIndex = pMap.get(preorder[preLeft]);
root.left=buildTree(preorder,pMap,preLeft+1,rootIndex-inLeft+preLeft,inLeft,rootIndex-1);
root.right=buildTree(preorder,pMap,rootIndex-inLeft+preLeft+1,preRight,rootIndex+1,inRight);
return root;
}
https://leetcode-cn.com/problems/binary-tree-preorder-traversal/
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
return pre(root,list);
}
public List<Integer> pre(TreeNode root,List<Integer>list){
if(root==null)return list;
list.add(root.val);
pre(root.left,list);
pre(root.right,list);
return list;
}
https://leetcode-cn.com/problems/invert-binary-tree/
public TreeNode invertTree(TreeNode root) {
if(root==null)return null;
TreeNode left =invertTree(root.left);
TreeNode right = invertTree(root.right);
root.left=right;
root.right=left;
return root;
}
https://leetcode-cn.com/problems/regular-expression-matching/
private Map<String, Boolean> memo = new HashMap<>();
public boolean isMatch(String s, String p) {
return dp(s, 0, p, 0);
}
private boolean dp(String s, int i, String p, int j) {
if (i == s.length()) {
if ((p.length() - j) % 2 == 1) {
return false;
}
for (; j + 1 < p.length(); j += 2) {
if (p.charAt(j + 1) != '*') {
return false;
}
}
return true;
}
if (j == p.length()) {
return i == s.length();
}
char[] charS = s.toCharArray();
char[] charP = p.toCharArray();
String key = i + "," + j;
if (memo.containsKey(key)) return memo.get(key);
boolean res;
if (charS[i] == charP[j] || charP[j] == '.') {
if (j + 1 < p.length() && charP[j + 1] == '*') {
res = dp(s, i, p, j + 2) || dp(s, i + 1, p, j);
} else {
res = dp(s, i + 1, p, j + 1);
}
} else {
if (j + 1 < p.length() && charP[j + 1] == '*') {
res = dp(s, i, p, j + 2);
} else {
res = false;
}
}
memo.put(key, res);
return res;
}
public int maxSubArray(int[] nums) {
if (nums.length == 0) return 0;
int[] dp = new int[nums.length];
dp[0] = nums[0];
int res = Integer.MIN_VALUE;
for (int i = 1; i < nums.length; i++) {
if (dp[i - 1] > 0) {
dp[i] = dp[i - 1] + nums[i];
} else {
dp[i] = nums[i];
}
res = Math.max(res, dp[i]);
}
return res;
}
//优化一下,可以不需要dp数组
public int maxSubArray2(int[] nums) {
if (nums.length == 0) return 0;
int dpNum = nums[0];
int res = dpNum;
for (int i = 1; i < nums.length; i++) {
if (dpNum > 0) {
dpNum += nums[i];
} else {
dpNum = nums[i];
}
res = Math.max(res, dpNum);
}
return res;
}
https://leetcode-cn.com/problems/jump-game/
public boolean canJump(int[] nums) {
if(nums==null)return true;
if(nums[0]==0&&nums.length>1)return false;
boolean flag=false;
for(int i = nums.length-2;i>0;i--){
if(nums[i]==0){
flag=false;
int step=0;
while(i>0){
step++;
i--;
if(nums[i]>step){
flag=true;
break;
}
}
if(!flag)return false;
}
}
return true;
}
https://leetcode-cn.com/problems/unique-paths/
62、63、64 都属于同一种类型的,可以一起做一下
public int uniquePaths(int m, int n) {
int dp[][]=new int [m][n];
for(int i =0;i<m;i++){
dp[i][0]=1;
}
for(int i =0;i<n;i++){
dp[0][i]=1;
}
for(int i =1;i<m;i++){
for(int j =1;j<n;j++){
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
return dp[m-1][n-1];
}
https://leetcode-cn.com/problems/unique-paths-ii/
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
if(obstacleGrid==null)return 0;
int row =obstacleGrid.length;
int column =obstacleGrid[0].length;
int[][]dp = new int[row][column];
if(obstacleGrid[0][0]==1)return 0;
dp[0][0]=1;
for(int i =1;i<row;i++){
if(obstacleGrid[i][0]!=1)dp[i][0]=dp[i-1][0];
}
for(int i =1;i<column;i++){
if(obstacleGrid[0][i]!=1)dp[0][i]=dp[0][i-1];
}
for(int i =1;i<row;i++){
for(int j =1;j<column;j++){
if(obstacleGrid[i][j]!=1)dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
return dp[row-1][column-1];
}
https://leetcode-cn.com/problems/minimum-path-sum/
public int minPathSum(int[][] grid) {
if(grid==null)return 0;
int row=grid.length;
int column=grid[0].length;
for(int i =1;i<row;i++){
grid[i][0]+=grid[i-1][0];
}
for(int i =1;i<column;i++){
grid[0][i]+=grid[0][i-1];
}
for(int i =1;i<row;i++){
for(int j =1;j<column;j++){
grid[i][j]+=Math.min(grid[i-1][j],grid[i][j-1]);
}
}
return grid[row-1][column-1];
}
https://leetcode-cn.com/problems/climbing-stairs/
public int climbStairs(int n){
if(n==0)return 0;
if(n==1)return 1;
int dp[] = new int[n+1];
dp[1]=1;
dp[2]=2;
for(int i = 3;i<=n;i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n];
}
https://leetcode-cn.com/problems/decode-ways/
这题用dp,主要是得理解切入点在判断一个字符和两个字符上。
public int numDecodings(String s) {
int length = s.length();
int[] dp = new int[length + 1];
dp[0]=1;
for (int i = 1; i <= length; i++) {
if(s.charAt(i-1)!='0'){
dp[i]+=dp[i-1];
}
if(i>1&&s.charAt(i-2)!='0'&&((s.charAt(i-2)-'0')*10+(s.charAt(i-1)-'0'))<=26){
dp[i]+=dp[i-2];
}
}
return dp[length];
}
https://leetcode-cn.com/problems/interleaving-string/
public boolean isInterleave(String s1, String s2, String s3) {
//不能这么判断
// if (s1.equals("")) return s2.equals(s3);
// if (s2.equals("")) return s1.equals(s3);
int n = s1.length(), m = s2.length(), t = s3.length();
if (n + m != t) {
return false;
}
boolean[][] dp = new boolean[n + 1][m + 1];
dp[0][0] = true;
for (int i = 0; i <= n; ++i) {
for (int j = 0; j <= m; ++j) {
int p = i + j - 1;
if (i > 0) {
dp[i][j] = dp[i][j] || (dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(p));
}
if (j > 0) {
dp[i][j] = dp[i][j] || (dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(p));
}
}
}
return dp[n][m];
}
https://leetcode-cn.com/problems/triangle/
public int minimumTotal(List<List<Integer>> triangle) {
int[][] dp = new int[triangle.size()][triangle.get(triangle.size() - 1).size()];
int res = Integer.MAX_VALUE;
dp[0][0] = triangle.get(0).get(0);
for (int i = 1; i < triangle.size(); i++) {
for (int i1 = 0; i1 < triangle.get(i).size(); i1++) {
dp[i][i1]=triangle.get(i).get(i1);
if (i1 == triangle.get(i).size() - 1) {
dp[i][i1] += dp[i - 1][i1 - 1]+triangle.get(i).get(i1);
continue;
}
if (i1 == 0) {
dp[i][i1] += (dp[i - 1][i1] + triangle.get(i).get(0));
} else {
dp[i][i1] += Math.min(dp[i - 1][i1], dp[i - 1][i1 - 1]) + triangle.get(i).get(i1);
}
}
}
for (int n = 0; n < dp.length; n++) {
res = Math.min(dp[dp.length - 1][n], res);
}
return res;
}
https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/
public int maxProfit(int[] prices) {
if (prices.length < 1) {
return 0;
}
int min = prices[0],dpValue=0;
for (int i = 0; i < prices.length; i++) {
if (prices[i] - min > dpValue) {
dpValue=prices[i] - min;
}
if(prices[i]<min){
min=prices[i];
}
}
return dpValue;
}
https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
dp和贪心算法均可。dp需要想到状态转移方程,贪心需要想到每天的股票价格并不影响。
public int maxProfit(int[] prices) {
if (prices.length<=1)return 0;
int[][] dp = new int[prices.length][2];
dp[0][0]=0;
dp[0][1]=-prices[0];
for (int i = 1; i <prices.length ; i++) {
dp[i][0]=Math.max(dp[i-1][1]+prices[i],dp[i-1][0]);
dp[i][1]=Math.max(dp[i-1][0]-prices[i],dp[i-1][1]);
}
return dp[prices.length-1][0];
}
public int maxProfit(int[] prices) {
if (prices.length<=1)return 0;
int res = 0;
for (int i = 1; i <prices.length; i++) {
res+=Math.max(0,prices[i]-prices[i-1]);
}
return res;
}
https://leetcode-cn.com/problems/maximum-product-subarray/
这题和53题相似,就是要注意复数乘以复数的情况,所以需要保存之前的最大最小值。
public int maxProduct(int[] nums) {
if(nums==null)return 0;
int maxP=nums[0];
int minP=nums[0];
int res = nums[0];
for(int i =1;i<nums.length;i++){
int tempMax=maxP,tempMin=minP;
maxP=Math.max(Math.max(nums[i],tempMax*nums[i]),tempMin*nums[i]);
minP=Math.min(Math.min(nums[i],tempMin*nums[i]),tempMax*nums[i]);
res=Math.max(maxP,res);
}
return res;
}
https://leetcode-cn.com/problems/house-robber/
// public int rob(int[] nums) {
// if(nums==null)return 0;
// if(nums.length==1)return nums[0];
// int dp[]=new int [nums.length];
// dp[0]=nums[0];
// dp[1]=nums[1];
// for(int i =2;i
// int max= 0;
// for(int j=0;j
// dp[i]=max=Math.max(dp[j]+nums[i],max);
// }
// }
// int max=0;
// for(int i =0;i
// max=Math.max(max,dp[i]);
// }
// return max;
// }
public int rob(int[] nums) {
if(nums==null)return 0;
if(nums.length==1)return nums[0];
int dp[]=new int[nums.length];
dp[0]=nums[0];
dp[1]=Math.max(nums[0],nums[1]);
for(int i =2;i<nums.length;i++){
dp[i]=Math.max(dp[i-1],dp[i-2]+nums[i]);
}
return dp[nums.length-1];
}
https://leetcode-cn.com/problems/house-robber-ii/
public int rob(int[] nums) {
if(nums==null)return 0;
if(nums.length==1)return nums[0];
return Math.max(robArr(nums,0,nums.length-1),robArr(nums,1,nums.length));
}
public int robArr(int [] nums,int start, int end){
int[] a = new int[end-start];
int sTemp=start;
for(int i =0;i<end-start;i++){
a[i]=nums[sTemp];
sTemp++;
}
return rob1(a);
}
public int rob1(int[] nums) {
if(nums==null)return 0;
if(nums.length==1)return nums[0];
int dp[]=new int[nums.length];
dp[0]=nums[0];
dp[1]=Math.max(nums[0],nums[1]);
for(int i =2;i<nums.length;i++){
dp[i]=Math.max(dp[i-1],dp[i-2]+nums[i]);
}
return dp[nums.length-1];
}
https://leetcode-cn.com/problems/longest-increasing-subsequence/
public int lengthOfLIS(int[] nums) {
if (nums.length < 1) return 0;
if (nums.length == 1) return 1;
int[] dp = new int[nums.length];
Arrays.fill(dp, 1);
for (int i = 0; i < nums.length; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
int res = 0;
for (int i = 0; i < nums.length; i++) {
res = Math.max(res, dp[i]);
}
return res;
}
https://leetcode-cn.com/problems/burst-balloons/
dp[i][j]:戳破第i个气球和第j个气球之间的所有气球得到的最大分数
public int maxCoins(int[] nums) {
if(nums==null)return 0;
int point[] = new int[nums.length+2];
point[0]=1;
point[nums.length+1]=1;
for (int i = 1; i <=nums.length ;i++) {
point[i]=nums[i-1];
}
int dp[][] = new int[nums.length+2][nums.length+2];
for (int i = point.length-2; i >=0 ; i--) {
for (int j = i+1; j <point.length ; j++) {
for (int k = i+1; k <j ; k++) {
dp[i][j]=Math.max(dp[i][j],dp[i][k]+dp[k][j]+point[i]*point[k]*point[j]);
}
}
}
return dp[0][point.length-1];
}
https://leetcode-cn.com/problems/coin-change/
public int coinChange(int[] coins, int amount) {
if (coins.length == 0) return -1;
int[] dp = new int[amount + 1];
Arrays.fill(dp, amount + 1);
dp[0] = 0;
for (int i = 1; i <= amount; ++i) {
for (int j = 0; j < coins.length; ++j) {
if (i >= coins[j]) {
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
}
}
}
return dp[amount] == amount + 1 ? -1 : dp[amount];
}
https://leetcode-cn.com/problems/russian-doll-envelopes/
public int maxEnvelopes(int[][] envelopes) {
Arrays.sort(envelopes, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
if(o1[0]!=o2[0])return o1[0]-o2[0];
if(o1[1]>=o2[1]) return -1;
else return 1;
}
});
int[] ints = new int[envelopes.length];
for (int i = 0; i < envelopes.length; i++) {
ints[i]=envelopes[i][1];
}
return findLengthOfLCIS(ints);
}
private int findLengthOfLCIS(int[] nums) {
if(nums.length<1)return 0;
if(nums.length==1)return 1;
int [] dp = new int[nums.length];
Arrays.fill(dp,1);
for(int i = 0;i<nums.length;i++){
for(int j=0;j<i;j++){
if(nums[i]>nums[j]){
dp[i]=Math.max(dp[i],dp[j]+1);
}
}
}
int res = 0;
for(int i = 0;i<nums.length;i++){
res = Math.max(res,dp[i]);
}
return res;
}
https://leetcode-cn.com/problems/longest-palindromic-subsequence/
//普通二位dp
public int longestPalindromeSubseq(String s) {
if(s.length()==0)return 0;
char[] chars = s.toCharArray();
int [][]dp = new int[chars.length][chars.length];
for (int i = 0; i < chars.length; i++) {
dp[i][i]=1;
}
for (int i = chars.length-2; i>=0 ; i--) {
for (int j = i+1; j <chars.length ; j++) {
if(chars[i]==chars[j])dp[i][j]=dp[i+1][j-1]+2;
else dp[i][j]=Math.max(dp[i][j-1],dp[i+1][j]);
}
}
return dp[0][chars.length-1];
}
//普通一维dp
public int longestPalindromeSubseq2(String s) {
if(s.length()==0)return 0;
char[] chars = s.toCharArray();
int []dp = new int[chars.length];
for (int i = 0; i < chars.length; i++) {
dp[i]=1;
}
for (int i = chars.length-2; i>=0 ; i--) {
int pre=0;
for (int j = i+1; j <chars.length ; j++) {
int temp = dp[j];
if(chars[i]==chars[j])dp[j]=pre+2;
else dp[j]=Math.max(dp[j-1],dp[j]);
pre =temp;
}
}
return dp[chars.length-1];
}
https://leetcode-cn.com/problems/super-egg-drop/
// 不能ac
Map<String,Integer>memo = new HashMap<>();
public int superEggDrop(int k, int n) {
return dp(k,n);
}
private int dp(int k, int n) {
if(k==1)return n;
if(n==0)return 0;
if(memo.containsKey(k+","+n))return memo.get(k+","+n);
int res = Integer.MAX_VALUE;
for (int i = 1; i <= n; i++) {
res=Math.min(res,Math.max(dp(k-1,i-1),dp(k,n-i))+1);
}
memo.put(k+","+n,res);
return res;
}
//二分搜索减枝
Map<String,Integer>memo = new HashMap<>();
public int superEggDrop(int k, int n) {
return dp(k,n);
}
private int dp(int k, int n) {
if(k==1)return n;
if(n==0)return 0;
if(memo.containsKey(k+","+n))return memo.get(k+","+n);
int res = Integer.MAX_VALUE;
int lo=1;
int high=n;
while(lo<=high){
int mid=(lo+high)>>1;
int broken = dp(k-1,mid-1);
int unBroken = dp(k,n-mid);
if(broken>unBroken){
high=mid-1;
res=Math.min(res,broken+1);
}else{
lo=mid+1;
res=Math.min(res,unBroken+1);
}
}
memo.put(k+","+n,res);
return res;
}
https://leetcode-cn.com/problems/minimum-insertion-steps-to-make-a-string-palindrome/
public int minInsertions(String s) {
if (s == null || s.length() == 0) {
return 0;
}
char[] chars = s.toCharArray();
int[] dp = new int[chars.length];
for (int i = dp.length - 2; i >= 0; i--) {
int pre =0;
for (int j = i + 1; j < chars.length; j++) {
int temp=dp[j];
if (chars[i] == chars[j]) dp[j] = pre;
else {
dp[j]=Math.min(dp[j],dp[j-1])+1;
}
pre =temp;
}
}
return dp[chars.length-1];
}
https://leetcode-cn.com/problems/a7VOhD/
//待优化
public int countSubstrings(String s) {
if (s == null || s.length() == 0) return 0;
char[] chars = s.toCharArray();
int[] dp = new int[chars.length];
int j = 0;
for (int i = 0; i < chars.length; i++) {
dp[i] = 1;
}
int count = chars.length;
for (int i = chars.length - 2; i >= 0; i--) {
int pre = 0;
for (j = i + 1; j < chars.length; j++) {
int temp = dp[j];
if (j - i == 1 && chars[i] == chars[j]) {
dp[j] = 1;
count += 1;
} else if (chars[i] == chars[j] && pre >= 1) {
dp[j] = 1;
count += 1;
}else {
dp[j]=0;
}
pre = temp;
}
}
return count;
}
https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/
public List<String> letterCombinations(String digits) {
List<String> lists = new ArrayList<>();
if (digits.length()<1)return lists;
Map<Character,String> map = new HashMap<>();
map.put('2', "abc");
map.put('3', "def");
map.put('4', "ghi");
map.put('5', "jkl");
map.put('6', "mno");
map.put('7', "pqrs");
map.put('8', "tuv");
map.put('9', "wxyz");
dfs(digits,0,"",lists,map);
return lists;
}
private void dfs(String digits, int start, String s, List<String> lists, Map<Character, String> map) {
if(start==digits.length()){
lists.add(s);
return;
}
char c = digits.charAt(start);
char[] tree = map.get(c).toCharArray();
for (int i = 0; i < tree.length; i++) {
dfs(digits,start+1, s+tree[i], lists,map);
}
return;
}
https://leetcode-cn.com/problems/balanced-binary-tree/
//法一:自顶向下计算长度
public boolean isBalanced(TreeNode root) {
if (root==null)return true;
return Math.abs(getCount(root.left,0)-getCount(root.right,0))<=1 ;
}
public int getCount(TreeNode root,int count){
if(root==null) return count;
count++;
return Math.max(getCount(root.left,count),getCount(root.right,count));
}
//法二:自低向上计算长度
public boolean isBalanced(TreeNode root) {
if (root == null) return true;
return height(root) >= 0;
}
private int height(TreeNode root) {
if (root == null) return 0;
int leftHeight =height(root.left);
int rightHeight =height(root.right);
if(leftHeight==-1||rightHeight==-1||Math.abs(leftHeight-rightHeight)>1){
return -1;
}
return Math.max(leftHeight,rightHeight)+1;
}
https://leetcode-cn.com/problems/divide-two-integers/
public int divide(int dividend, int divisor) {
// 考虑被除数为最小值的情况
if (dividend == Integer.MIN_VALUE) {
if (divisor == 1) {
return Integer.MIN_VALUE;
}
if (divisor == -1) {
return Integer.MAX_VALUE;
}
}
// 考虑除数为最小值的情况
if (divisor == Integer.MIN_VALUE) {
return dividend == Integer.MIN_VALUE ? 1 : 0;
}
// 考虑被除数为 0 的情况
if (dividend == 0) {
return 0;
}
// 一般情况,使用二分查找
// 将所有的正数取相反数,这样就只需要考虑一种情况
boolean rev = false;
if (dividend > 0) {
dividend = -dividend;
rev = !rev;
}
if (divisor > 0) {
divisor = -divisor;
rev = !rev;
}
int left = 1, right = Integer.MAX_VALUE, ans = 0;
while (left <= right) {
// 注意溢出,并且不能使用除法
int mid = left + ((right - left) >> 1);
boolean check = quickAdd(divisor, mid, dividend);
if (check) {
ans = mid;
// 注意溢出
if (mid == Integer.MAX_VALUE) {
break;
}
left = mid + 1;
} else {
right = mid - 1;
}
}
return rev ? -ans : ans;
}
// 快速乘
//用来判断z*y是否已经超过了x
public boolean quickAdd(int y, int z, int x) {
// x 和 y 是负数,z 是正数
int result = 0, add = y;
while (z != 0) {
//z是单数的情况
if ((z & 1) != 0) {
// 需要保证 result + add >= x
if (result < x - add) {
return false;
}
result += add;
}
if (z != 1) {
// 需要保证 add + add >= x
if (add < x - add) {
return false;
}
//应为后面对z取一半,所以需要双倍加
add += add;
}
// 不能使用除法
z >>= 1;
}
return true;
}
https://leetcode-cn.com/problems/permutations/
private List<List<Integer>>res =new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
if(nums.length==0){
return new ArrayList<>();
}
List<Integer> track = new ArrayList<>();
backTrack(nums,track);
return res;
}
private void backTrack(int[] nums, List<Integer> track) {
if(nums.length==track.size()){
res.add(new ArrayList<>(track));
return;
}
for (int i = 0; i < nums.length; i++) {
if (track.contains((Integer)nums[i])) {
continue;
}
track.add(nums[i]);
backTrack(nums,track);
track.remove((Integer)nums[i]);
}
}
https://leetcode-cn.com/problems/n-queens/
class Solution {
public List<List<String>> solveNQueens(int n) {
List<List<String>> solutions = new ArrayList<List<String>>();
//由于java操作链表比较麻烦,这里queen用来记录i行的Q元素的列标
int[] queens = new int[n];
Arrays.fill(queens, -1);
//用来记录行元素是否含有Q
Set<Integer> columns = new HashSet<Integer>();
//用来记录该元素左上角元素是否含有Q
Set<Integer> diagonals1 = new HashSet<Integer>();
//用来记录该元素右上角元素是否含有Q
Set<Integer> diagonals2 = new HashSet<Integer>();
backtrack(solutions, queens, n, 0, columns, diagonals1, diagonals2);
return solutions;
}
public void backtrack(List<List<String>> solutions, int[] queens, int n, int row, Set<Integer> columns, Set<Integer> diagonals1, Set<Integer> diagonals2) {
if (row == n) {
List<String> board = generateBoard(queens, n);
solutions.add(board);
} else {
for (int i = 0; i < n; i++) {
//这三个判断太妙了
if (columns.contains(i)) {
continue;
}
int diagonal1 = row - i;
if (diagonals1.contains(diagonal1)) {
continue;
}
int diagonal2 = row + i;
if (diagonals2.contains(diagonal2)) {
continue;
}
//添加
queens[row] = i;
columns.add(i);
diagonals1.add(diagonal1);
diagonals2.add(diagonal2);
//继续下一行
backtrack(solutions, queens, n, row + 1, columns, diagonals1, diagonals2);
//复原
queens[row] = -1;
columns.remove(i);
diagonals1.remove(diagonal1);
diagonals2.remove(diagonal2);
}
}
}
//生成整个棋盘
public List<String> generateBoard(int[] queens, int n) {
List<String> board = new ArrayList<String>();
for (int i = 0; i < n; i++) {
char[] row = new char[n];
Arrays.fill(row, '.');
row[queens[i]] = 'Q';
board.add(new String(row));
}
return board;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/n-queens/solution/nhuang-hou-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/
这题标准的BFS,也可以用DFS。
//BFS
public int minDepth(TreeNode root) {
if(root==null)return 0;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
int num=1;
while (!queue.isEmpty()){
int sz =queue.size();
for (int i = 0; i < sz; i++) {
TreeNode cur =queue.poll();
if(cur.left==null&&cur.right==null)return num;
if(cur.left!=null){
queue.add(cur.left);
}
if(cur.right!=null){
queue.add(cur.right);
}
}
num++;
}
return num;
}
// public int minDepth(TreeNode root) {
// if (root == null) return 0;
// if (root.left == null && root.right == null) return 1;
// int min = Integer.MAX_VALUE;
// int left=Integer.MAX_VALUE;
// if(root.left!=null){
// left = minDepth(root.left);
// }
// int right=Integer.MAX_VALUE;
// if(root.right!=null) {
// right = Math.min(minDepth(root.right),min);
// }
// return Math.min(left, right) + 1;
// }
https://leetcode-cn.com/problems/zlDJc7/
//会了BFS框架,整道题就比较好理解
public int openLock(String[] deadends, String target) {
Set<String> dead = new HashSet<>();
for (String deadend : deadends) {
dead.add(deadend);
}
Queue<String> queue = new LinkedList<>();
Set<String> visited = new HashSet<>();
int step = 0;
queue.offer("0000");
visited.add("0000");
while (!queue.isEmpty()){
int size = queue.size();
for (int i = 0; i < size; i++) {
String cur = queue.poll();
if (dead.contains(cur))
continue;
if (cur.equals(target)) {
return step;
}
for (int j = 0; j < 4; j++) {
String up =upOne(cur, j);
if(!visited.contains(up)){
queue.offer(up);
visited.add(up);
}
String down =downOne(cur, j);
if(!visited.contains(down)){
queue.offer(down);
visited.add(down);
}
}
}
step++;
}
return -1;
}
//可以先从这开始写
String upOne(String target, int targetNum) {
char[] chars = target.toCharArray();
if (chars[targetNum] == '9') {
chars[targetNum] = '0';
} else {
chars[targetNum] += 1;
}
return new String(chars);
}
String downOne(String target, int targetNum) {
char[] chars = target.toCharArray();
if (chars[targetNum] == '0') {
chars[targetNum] = '9';
} else {
chars[targetNum] -= 1;
}
return new String(chars);
}
https://leetcode-cn.com/problems/c32eOV/
public ListNode detectCycle(ListNode head) {
ListNode fast=head,slow=head;
while (fast != null && fast.next != null) {
fast=fast.next.next;
slow=slow.next;
if(slow==fast)break;
}
//注意这里需要判断一下
if(fast==null||fast.next==null)return null;
slow=head;
while (slow != fast) {
slow=slow.next;
fast=fast.next;
}
return slow;
}
https://leetcode-cn.com/problems/minimum-size-subarray-sum/
public int minSubArrayLen(int target, int[] nums) {
if (nums.length == 0) return 0;
int start = 0, end = 0;
int sub = 0;
int res = Integer.MAX_VALUE;
while (end < nums.length) {
sub += nums[end];
end++;
while (sub >= target) {
sub -= nums[start];
res = Math.min(res, end-start);
start++;
}
}
return res==Integer.MAX_VALUE?0:res;
}