代码随想录
- 1.数组部分
- 2. 链表部分
- 3.哈希表
- 4.字符串
- 5双指针
- 6.栈与队列
- 7.二叉树
- 7.1 二叉树的递归遍历
- 7.2 二叉树的迭代遍历
- 7.3二叉树的层序遍历
- 7.4二叉树的层序遍历II
- 7.5二叉树的右视图
- 7.6二叉树的层平均值
- 7.7N叉树的层序遍历
- 7.8树中每行得最大值
- 7.9返回二叉树的最大深度
- 7.10二叉树得最小深度
- 7.11反转二叉树
- 7.12对称二叉树
- 7.13完全二叉树节点的个数
- 7.14平衡二叉树
- 7.15二叉树的所有路径
- 7.16二叉树左叶子的和
- 7.17找树左下角的值
- 7.18 路径总和
- 7.19从中序后序序列构造二叉树
- 7.20最大二叉树
- 7.21合并二叉树
- 7.22BST中的搜索
- 7.23验证二叉搜索树**
- 7.24二叉搜索树的绝对差
- 7.25二叉搜索树中的众数**
- 7.26二叉搜索树中最近公共祖先
- 7.27二叉搜索树的插入
- 7.28二叉搜索树的删除**
- 7.29修剪二叉搜索树**
- 7.30将有序数组转换为二叉搜索树
- 7.31 将二叉搜索树转换为累加树
- 8.回溯算法
- 9.贪心算法
- 10.动态规划
1.数组部分
1.1二分查找
class Solution {
public int search(int[] nums, int target) {
if(nums.length==0)return -1;
int l=0,r=nums.length-1;
while(l<=r){
int mid=l+r>>1;
if(nums[mid]==target){
return mid;
}else if(nums[mid]<target){
l=mid+1;
}else{
r=mid-1;
}
}
return -1;
}
}
1.2移除元素
class Solution {
//双指针算法
public int removeElement(int[] nums, int val) {
int i=0;//标记目前位置
for(int j=0;j<nums.length;j++){
if(nums[j]!=val){
nums[i]=nums[j];
i++;
}
}
return i;
}
}
1.3 有序数组的平方
class Solution {
public int[] sortedSquares(int[] nums) {
int n=nums.length;
int[] ans=new int[n];
int k=n-1;
int i=0,j=nums.length-1;
//类似于归并排序
while(i<=j){
if(nums[i]*nums[i]<nums[j]*nums[j]){
ans[k--]=nums[j]*nums[j];
j--;
}else{
ans[k--]=nums[i]*nums[i];
i++;
}
}
return ans;
}
}
1.4长度最小的子数组
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int minlen=0x3f3f3f3f;
int sum=0;
int j=0;
for(int i=0;i<nums.length;i++){
sum+=nums[i];
while(sum>=target){//缩小区间
minlen=Math.min(minlen,i-j+1);
sum-=nums[j];
j++;//
}
}
if(minlen==0x3f3f3f3f)return 0;
return minlen;
}
}
1.5螺旋矩阵II
class Solution {
static boolean[][] st;
public int[][] generateMatrix(int n) {
st=new boolean[n][n];
int[] dx={0,1,0,-1},dy={1,0,-1,0};
int[][] ans=new int[n][n];
int x=0,y=0,d=0;//横,纵坐标,转向指针
for(int i=1;i<=n*n;i++){
ans[x][y]=i;
st[x][y]=true;
int a=x+dx[d],b=y+dy[d];
if(a<0 || a>=n || b<0 || b>=n || st[a][b]){
d=(d+1)%4;
a=x+dx[d];
b=y+dy[d];
}
x=a;
y=b;
}
return ans;
}
}
2. 链表部分
2.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 removeElements(ListNode head, int val) {
if(head==null)return null;
ListNode dummy=new ListNode(-1);
dummy.next=head;
ListNode cur=dummy;
while(cur.next!=null){
if(cur.next.val==val){
cur.next=cur.next.next;
}else cur=cur.next;
}
return dummy.next;
}
}
2.2设计链表
2.3反转链表
/**
* 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 reverseList(ListNode head) {
ListNode pre=null;
ListNode cur=head;
while(cur!=null){
ListNode next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
return pre;
}
}
2.4两两交换相邻的节点
/**
* 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 swapPairs(ListNode head) {
ListNode dummy=new ListNode(-1);
dummy.next=head;
ListNode cur=dummy;
while(cur.next!=null && cur.next.next!=null){
ListNode a=cur.next;
ListNode b=cur.next.next;
cur.next=b;
a.next=b.next;
b.next=a;
cur=a;
}
return dummy.next;
}
}
2.5删除链表的倒数第n个节点
/**
* 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 removeNthFromEnd(ListNode head, int n) {
ListNode dummy=new ListNode(-1);
dummy.next=head;
ListNode cur=head;
int cnt=0;
while(cur!=null){
cnt++;
cur=cur.next;
}
cur=dummy;
cnt=cnt-n;
while(cnt-->0)cur=cur.next;
cur.next=cur.next.next;
return dummy.next;
}
}
2.6环形链表II
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow=hasCycle(head);
if(slow==null)return null;
else{
ListNode fast=head;
while(fast!=slow){
fast=fast.next;
slow=slow.next;
}
}
return slow;
}
public static ListNode hasCycle(ListNode head){
ListNode slow=head;
ListNode fast=head;
while(fast!=null && fast.next!=null){
fast=fast.next.next;
slow=slow.next;
if(fast==slow)return slow;
}
return null;
}
}
2.7链表相交
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA==null || headB==null)return null;
int lenA=len(headA);
int lenB=len(headB);
ListNode curA=headA;
ListNode curB=headB;
if(lenA>lenB){
int t=lenA-lenB;
for(int i=0;i<t;i++){
curA=curA.next;
}
while(curA!=null && curA!=curB){
curA=curA.next;
curB=curB.next;
}
return curA;
}else{
int t=lenB-lenA;
for(int i=0;i<t;i++){
curB=curB.next;
}
while(curA!=null && curA!=curB){
curA=curA.next;
curB=curB.next;
}
return curA;
}
}
public static int len(ListNode head){
int cnt=0;
ListNode cur=head;
while(cur!=null){
cnt++;
cur=cur.next;
}
return cnt;
}
}
3.哈希表
3.1有效的字母异位词
class Solution {
//可以进一步优化,一个+一个- 判断是否为0
public boolean isAnagram(String s, String t) {
int[] cnts=help(s);
int[] cntt=help(t);
for(int i=0;i<26;i++){
if(cnts[i]!=cntt[i])return false;
}
return true;
}
//字符统计
public static int[] help(String str){
char[] ch=str.toCharArray();
int[] cnt=new int[26];
for(int i=0;i<ch.length;i++){
cnt[ch[i]-'a']++;
}
return cnt;
}
}
3.2两个数组的交集
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
ArrayList<Integer> ans=new ArrayList<>();
boolean[] st=new boolean[1010];
for(int num:nums1){
st[num]=true;
}
for(int num:nums2){
if(st[num]){
ans.add(num);
st[num]=false;
}
}
int[] res=new int[ans.size()];
for(int i=0;i<ans.size();i++){
res[i]=ans.get(i);
}
return res;
}
}
3.3欢乐数
class Solution {
//双指针或者统计出现过的数
public boolean isHappy(int n) {
Set<Integer> set=new HashSet<>();
while(n!=1 && !set.contains(n)){
set.add(n);
// System.out.println(n);
n=get(n);
}
return n==1;
}
public static int get(int x){
int res=0;
while(x!=0){
int t=x%10;
res+=t*t;
x/=10;
}
return res;
}
}
3.4快乐数
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> map=new HashMap<>();
for(int i=0;i<nums.length;i++){
if(map.containsKey(target-nums[i]) )return new int[]{map.get(target-nums[i]),i};
map.put(nums[i],i);
}
return new int[]{-1,-1};
}
}
3.5两数之和
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> map=new HashMap<>();
for(int i=0;i<nums.length;i++){
if(map.containsKey(target-nums[i]) )return new int[]{map.get(target-nums[i]),i};
map.put(nums[i],i);
}
return new int[]{-1,-1};
}
}
3.6四数相加
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
HashMap<Integer,Integer> map=new HashMap<>();
int res=0;
int n=nums1.length;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
int t=nums1[i]+nums2[j];
map.put(-t,map.getOrDefault(-t,0)+1);
}
}
//优化得到On^2
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
int num=nums3[i]+nums4[j];
if(map.containsKey(num))res+=map.get(num);
}
}
return res;
}
}
3.7赎金信
*
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int[] cnt=new int[26];
char[] chm=magazine.toCharArray();
for(char c:chm){
cnt[c-'a']++;
}
char[] chr=ransomNote.toCharArray();
for(char c:chr){
cnt[c-'a']--;
}
for(int i=0;i<26;i++){
if(cnt[i]<0)return false;
}
return true;
}
}
3.8三数之和
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> ans=new ArrayList<>();
for(int i=0;i<nums.length-1;i++){
//排序之后如果第一个元素大于0,则无论任何组合都不能符合要求
if(nums[i]>0)return ans;
if( i>0 && nums[i]==nums[i-1])continue;//对第一个数进行去重
//针对[i+1,n-1]我们可以使用双指针算法
int j=i+1,k=nums.length-1;
while(j<k){
int sum=nums[i]+nums[j]+nums[k];
if(sum>0){
k--;
}else if(sum<0){
j++;
}else{
//符合要求后我们将加入答案
ans.add(Arrays.asList(nums[i],nums[j],nums[k]));
while(j<k && nums[j]==nums[j+1])j++;
while(j<k && nums[k]==nums[k-1])k--;
k--;
j++;
}
}
}
//对i的去重
return ans;
}
}
3.9四数之和
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
// target=(long)target;
List<List<Integer>> ans=new ArrayList<>();
Arrays.sort(nums);
int n=nums.length;
for(int i=0;i<n-3;i++){
if(i>0 && nums[i]==nums[i-1])continue;
if(nums[i]>0 && nums[i]>target)return ans;
for(int j=i+1;j<n-2;j++){
if(j>i+1&& nums[j]==nums[j-1])continue;
int l=j+1,r=n-1;
while(l<r){
long sum=(long)(nums[i]+nums[j]+nums[l]+nums[r]);
if(sum>Integer.MAX_VALUE)continue;
if(sum>target){
r--;
}else if(sum<target){
l++;
}else if(sum==target){
ans.add(Arrays.asList(nums[i],nums[j],nums[l],nums[r]));
while(l<r && nums[r]==nums[r-1]){
r--;
}
while(l<r && nums[l]==nums[l+1]){
l++;
}
l++;
r--;
}
}
}
}
return ans;
}
}
4.字符串
4.1反转字符串
class Solution {
public void reverseString(char[] s) {
int i=0,j=s.length-1;
char tmp='a';
while(i<j){
tmp=s[i];
s[i]=s[j];
s[j]=tmp;
i++;
j--;
}
}
}
4.2反转字符串II
class Solution {
public String reverseStr(String s, int k) {
char[] ch=s.toCharArray();
int n=ch.length;
int tmp=n/(2*k);
for(int i=0;i<tmp;i++){
int l=0+i*2*k;
int r=l+k-1;
while(l<r){
char t=ch[l];
ch[l]=ch[r];
ch[r]=t;
l++;
r--;
}
}
// System.out.println(n%(2*k));
int l=tmp*2*k;
int r=n-1;
if(n%(2*k)>=k){
l=0+tmp*2*k;
r=l+k-1;
}
while(l<r){
char t=ch[l];
ch[l]=ch[r];
ch[r]=t;
l++;
r--;
}
return new String(ch);
}
}
4.3替换空格
class Solution {
public String replaceSpace(String s) {
StringBuilder sb=new StringBuilder();
for(int i=0;i<s.length();i++){
if(s.charAt(i)==' '){
sb.append("%20");
}else{
sb.append(s.charAt(i));
}
}
return new String(sb);
}
}
4.4反转字符串里的单词
class Solution {
public String reverseWords(String s) {
if(s.length()==0)return "";
int i=0,j=s.length()-1;
while(i<s.length() && s.charAt(i)==' ')i++;
while(j>=0 && s.charAt(j)==' ')j--;
if(i>j)return "";
StringBuilder sb=new StringBuilder();
//直接使用StringBuilder进行遍历,去除空格
while(i<=j){
char c=s.charAt(i);
//这里第二个条件十分巧妙,当有连续两个空格是,只会加第一个
if(c!=' ' || sb.charAt(sb.length()-1)!=' ')sb.append(c);
i++;
}
//反转整个字符串
reverse(sb,0,sb.length()-1);
//反转单个单词
i=0;
while(i<sb.length()){
j=i;
while(j<sb.length() && sb.charAt(j)!=' ')j++;
reverse(sb,i,j-1);
i=j+1;
}
return sb.toString();
}
//反转指定区间的字符串[]
public StringBuilder reverse(StringBuilder sb,int l,int r){
while(l<r){
char t=sb.charAt(l);
sb.setCharAt(l,sb.charAt(r));
sb.setCharAt(r,t);
l++;
r--;
}
return sb;
}
}
思路解析
if(c!=' ' || sb.charAt(sb.length()-1)!=' ')sb.append(c);
:第二个条件确保我们可以单词间只加一个空格,值得注意
整体思路在于:去空,先将整个单词反转,而后逐个反转每个单词
- 该方法尽管只是O(n)级别的复杂度,但是需要扫描两边,我们接下来看一中只需要扫描一遍的做法
class Solution {
//代码整体更加简洁
public String reverseWords(String s) {
char[] sc=s.toCharArray();
StringBuilder sb=new StringBuilder();
//去除首尾空格
int left=0,right=sc.length-1;
while(sc[left]==' ')left++;
while(sc[right]==' ')right--;
//right永远指向当前单词的最后一个位置,
//index+1:用来搜寻,当前单词的第一个位置(index定位到空格)
while(left<=right){
//倒着扫描
int index=right;
//确定最后一个单词的起始位置
while(index>=left && sc[index]!=' ')index--;
for(int i=index+1;i<=right;i++){
sb.append(sc[i]);
}
//如果不是第一个单词,后面加一个空格
if(index>left)sb.append(' ');
//指针移动至下一个单词的末尾
while(index>=left && sc[index]==' ')index--;
right=index;
}
return sb.toString();
}
}
4.5左旋字符串
class Solution {
public String reverseLeftWords(String s, int n) {
char[] ch=s.toCharArray();
StringBuilder sb=new StringBuilder();
for(int i=0;i<ch.length;i++){
sb.append(ch[(n)%ch.length]);
n=n+1;
}
return sb.toString();
}
}
4.6找出字符串中第一个匹配项的下标
思路分析
- 经典的KMP算法,直接使用即可
class Solution {
//KMP算法
static int[] next;
public int strStr(String haystack, String needle) {
int n=haystack.length();
int m=needle.length();
char[] ch=(" "+haystack).toCharArray();
char[] cn=(" "+needle).toCharArray();
next=new int[cn.length];
next(cn);
for(int i=1,j=0;i<=n;i++){
while(j!=0 && ch[i]!=cn[j+1])j=next[j];
if(ch[i]==cn[j+1])j++;
if(j==m)return (i-m);
}
return -1;
}
public static void next(char[] ch){
int n=ch.length;
//next[1]指定为0
for(int i=2,j=0;i<n;i++){
while(j!=0 && ch[i]!=ch[j+1])j=next[j];
if(ch[i]==ch[j+1])j++;
next[i]=j;
}
}
}
4.7重复的子字符串
class Solution {
public boolean repeatedSubstringPattern(String s) {
int n=s.length();
char[] ch=(" "+s).toCharArray();
int[] ne=new int[n+1];
for(int i=2,j=0;i<=n;i++){
while(j!=0 && ch[i]!=ch[j+1])j=ne[j];
if(ch[i]==ch[j+1])j++;
ne[i]=j;
}
int t=n-ne[n];
return (t<n && n%t==0);
}
}
5双指针
5.1移除元素
- 快慢指针
class Solution {
public int removeElement(int[] nums, int val) {
//一个指针指向当前位置,一个指向需要更换的位置
int n=nums.length;
int i=0,j=0;
while(j<n){
while(j<n && nums[j]==val)j++;
// System.out.println(i+" "+j);
if(j>=n)break;
int t=nums[i];
nums[i]=nums[j];
nums[j]=t;
j++;
i++;
}
return i;
}
}
5.2反转字符串
class Solution {
public void reverseString(char[] s) {
int i=0,j=s.length-1;
while(i<j){
char t=s[i];
s[i]=s[j];
s[j]=t;
i++;
j--;
}
// return s;
}
}
5.3反转字符串中的单词
class Solution {
public String reverseWords(String s) {
char[] ch=s.toCharArray();
int l=0,r=s.length()-1;
//去除首尾空格
while(ch[l]==' ')l++;
while(ch[r]==' ')r--;
//倒着扫描
StringBuilder sb=new StringBuilder();
while(l<=r){
int i=r;
while(i>=l && ch[i]!=' ')i--;
for(int j=i+1;j<=r;j++)sb.append(ch[j]);
if(i>l)sb.append(" ");
//指针移动
r=i;
//移到下一个单词末尾
while(r>=l && ch[r]==' ')r--;
}
return new String(sb);
}
}
5.4反转链表
/**
* 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 reverseList(ListNode head) {
ListNode pre=null;
ListNode cur=head;
while(cur!=null){
ListNode next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
return pre;
}
}
5.5删除链表的倒数第n个节点
/**
* 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 removeNthFromEnd(ListNode head, int n) {
ListNode dummy=new ListNode(-1);
dummy.next=head;
ListNode fast=dummy;
ListNode slow=dummy;
for(int i=0;i<=n;i++)fast=fast.next;
while(fast!=null){
slow=slow.next;
fast=fast.next;
}
slow.next=slow.next.next;
return dummy.next;
}
}
6.栈与队列
6.1用栈实现队列
class MyQueue {
static ArrayDeque<Integer> sta;
static ArrayDeque<Integer> h;
public MyQueue() {
sta=new ArrayDeque<>();
h=new ArrayDeque<>();
}
public void push(int x) {
sta.push(x);
}
public int pop() {
if(!h.isEmpty()){
return h.pop();
}else{
while(!sta.isEmpty()){
h.push(sta.pop());
}
}
return h.pop();
}
public int peek() {
if(!h.isEmpty()){
return h.peek();
}else{
while(!sta.isEmpty()){
h.push(sta.pop());
}
}
return h.peek();
}
public boolean empty() {
return sta.isEmpty()&&h.isEmpty();
}
}
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue obj = new MyQueue();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.peek();
* boolean param_4 = obj.empty();
*/
6.2用队列模拟栈
class MyStack {
ArrayDeque<Integer> q;
public MyStack() {
q=new ArrayDeque<>();
}
public void push(int x) {
q.offer(x);
int size=q.size();
size--;
while(size-->0){
q.offer(q.poll());
}
}
public int pop() {
return q.poll();
}
public int top() {
return q.peek();
}
public boolean empty() {
return q.isEmpty();
}
}
/**
* Your MyStack object will be instantiated and called as such:
* MyStack obj = new MyStack();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.top();
* boolean param_4 = obj.empty();
*/
6.3有效得括号
6.4 删除字符串中所有相邻得重复项
6.5逆波兰表达式求值
class Solution {
public int evalRPN(String[] tokens) {
ArrayDeque<Integer> sta=new ArrayDeque<>();
for(int i=0;i<tokens.length;i++){
if(isNumeric(tokens[i]))sta.push(Integer.parseInt(tokens[i]));
else{
int b=sta.pop();
int a=sta.pop();
sta.push(cal(a,b,tokens[i]));
}
}
return sta.pop();
}
public int cal(int a,int b,String m){
if(m.equals("+"))return a+b;
if(m.equals("-"))return a-b;
if(m.equals("*"))return a*b;
if(m.equals("/"))return a/b;
return 0;
}
public static boolean isNumeric(String str) {
return str.matches("-?\\d+(\\.\\d+)?"); // 使用正则表达式判断是否为数字
}
}
6.6滑动窗口最大值
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int n=nums.length;
int m=0;
int[] ans=new int[n-k+1];
ArrayDeque<Integer> q=new ArrayDeque<>();
for(int i=0;i<nums.length;i++){
if(!q.isEmpty() && i-q.peek()>=k)q.poll();
while(!q.isEmpty()&& nums[i]>=nums[q.peekLast()]){
// if(i==3)System.out.println(nums[q.peek()]);
q.pollLast();
}
q.offer(i);
if(i>=k-1){
ans[m++]=nums[q.peek()];
}
}
return ans;
}
}
6.7前k个高频元素
class Solution {
public int[] topKFrequent(int[] nums, int k) {
PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> o1[1] - o2[1]);
Map<Integer,Integer> map=new HashMap<>();
for(int num:nums)map.put(num,map.getOrDefault(num,0)+1);
for(var x:map.entrySet()){
int[] tmp=new int[2];
tmp[0]=x.getKey();
tmp[1]=x.getValue();
pq.add(tmp);
}
while(pq.size()>k)pq.poll();
int[] ans=new int[k];
for(int i=0;i<k;i++){
ans[i]=pq.poll()[0];
}
return ans;
}
}
7.二叉树
7.1 二叉树的递归遍历
前序遍历
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<>();
pre(res,root);
return res;
}
static void pre(List<Integer> res,TreeNode root){
if(root==null)return;
res.add(root.val);
pre(res,root.left);
pre(res,root.right);
}
}
后序遍历
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
//迭代解决
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> ans=new ArrayList<>();
posOrder(root,ans);
return ans;
}
private void posOrder(TreeNode root,List<Integer> ans){
if(root==null){
return;
}
posOrder(root.left,ans);
posOrder(root.right,ans);
ans.add(root.val);
}
}
中序遍历
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<>();
in(root,res);
return res;
}
static void in(TreeNode root,List<Integer> res){
if(root==null)return;
in(root.left,res);
res.add(root.val);
in(root.right,res);
}
}
7.2 二叉树的迭代遍历
前序遍历
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<>();
if(root==null)return res;
ArrayDeque<TreeNode> sta=new ArrayDeque<>();
sta.push(root);
while(!sta.isEmpty()){
TreeNode t=sta.pop();
res.add(t.val);
if(t.right!=null)sta.push(t.right);
if(t.left!=null)sta.push(t.left);
}
return res;
}
}
后序遍历
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<>();
if(root==null)return res;
ArrayDeque<TreeNode> sta=new ArrayDeque<>();
sta.push(root);
while(!sta.isEmpty()){
TreeNode t=sta.pop();
res.add(0,t.val);
//因为我们要进行反转,所以先入左节点,后右节点,弹出(右左),反转(左右)
if(t.left!=null)sta.push(t.left);
if(t.right!=null)sta.push(t.right);
}
return res;
}
}
中序遍历
Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<>();
ArrayDeque<TreeNode> sta=new ArrayDeque<>();
while(root!=null || !sta.isEmpty()){
while(root!=null){//只要结点的左子树不空,就向左遍历
sta.push(root);
root=root.left;
}
if(!sta.isEmpty()){//将所有的左子树节点加入之后我们进行遍历
root=sta.pop();//将当前栈顶元素弹出
res.add(root.val);//遍历该元素
root=root.right;//遍历该元素的右子树
}
}
return res;
}
}
7.3二叉树的层序遍历
/**
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ans=new ArrayList<>();
if(root==null)return ans;
ArrayDeque<TreeNode> q=new ArrayDeque<>();
q.offer(root);
while(!q.isEmpty()){
int size=q.size();
List<Integer> level=new ArrayList<>();
for(int i=0;i<size;i++){
TreeNode t=q.poll();
level.add(t.val);
if(t.left!=null)q.offer(t.left);
if(t.right!=null)q.offer(t.right);
}
ans.add(level);
}
return ans;
}
}
7.4二叉树的层序遍历II
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> ans=new ArrayList<>();
if(root==null)return ans;
ArrayDeque<TreeNode> q=new ArrayDeque<>();
q.offer(root);
while(!q.isEmpty()){
int size=q.size();
List<Integer> level=new ArrayList<>();
for(int i=0;i<size;i++){
TreeNode t=q.poll();
level.add(t.val);
if(t.left!=null)q.offer(t.left);
if(t.right!=null)q.offer(t.right);
}
ans.add(0,level);
}
return ans;
}
}
7.5二叉树的右视图
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> ans=new ArrayList<>();
ArrayDeque<TreeNode> q=new ArrayDeque<>();
if(root==null)return ans;
q.offer(root);
while(!q.isEmpty()){
int size=q.size();
for(int i=0;i<size;i++){
TreeNode t=q.poll();
if(i==size-1)ans.add(t.val);
if(t.left!=null)q.offer(t.left);
if(t.right!=null)q.offer(t.right);
}
}
return ans;
}
}
7.6二叉树的层平均值
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> ans=new ArrayList<>();
ArrayDeque<TreeNode> q=new ArrayDeque<>();
if(root==null)return ans;
q.offer(root);
while(!q.isEmpty()){
int size=q.size();
double sum=0;
for(int i=0;i<size;i++){
TreeNode t=q.poll();
sum+=(double)t.val;
if(t.left!=null)q.offer(t.left);
if(t.right!=null)q.offer(t.right);
if(i==size-1)ans.add(sum/(double)size);
}
}
return ans;
}
}
7.7N叉树的层序遍历
/*
// Definition for a Node.
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public List<List<Integer>> levelOrder(Node root) {
List<List<Integer>> ans=new ArrayList<>();
ArrayDeque<Node> q=new ArrayDeque<>();
if(root==null)return ans;
q.offer(root);
while(!q.isEmpty()){
int size=q.size();
List<Integer> level=new ArrayList<>();
for(int i=0;i<size;i++){
Node t=q.poll();
level.add(t.val);
for(Node node:t.children){
if(node!=null)q.offer(node);
}
}
ans.add(level);
}
return ans;
}
}
7.8树中每行得最大值
class Solution {
public List<Integer> largestValues(TreeNode root) {
ArrayList<Integer> ans=new ArrayList<>();
ArrayDeque<TreeNode> q=new ArrayDeque<TreeNode>();
if(root==null)return ans;
q.offer(root);
while(!q.isEmpty()){
int size=q.size();
int max=q.peek().val;
for(int i=0;i<size;i++){
TreeNode t=q.poll();
max=Math.max(max,t.val);
if(t.left!=null)q.offer(t.left);
if(t.right!=null)q.offer(t.right);
}
ans.add(max);
}
return ans;
}
}
7.9返回二叉树的最大深度
class Solution {
public int maxDepth(TreeNode root) {
return dfs(root);
}
public static int dfs(TreeNode root){
if(root==null)return 0;
return Math.max(dfs(root.left),dfs(root.right))+1;
}
}
7.10二叉树得最小深度
class Solution {
//注意最小深度得定义:最近得叶子节点到根节点得节点数量
public int minDepth(TreeNode root) {
if(root==null)return 0;
//左右全为空
if(root.left==null && root.right==null)return 1;
//左右一个为空
if(root.left==null || root.right==null)return minDepth(root.left)+minDepth(root.right)+1;
if(root.left!=null && root.right!=null)return Math.min(minDepth(root.left),minDepth(root.right))+1;
return 0;
}
}
7.11反转二叉树
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root==null)return root;
TreeNode t=root.left;
root.left=root.right;
root.right=t;
invertTree(root.left);
invertTree(root.right);
return root;
}
}
7.12对称二叉树
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root==null)return true;
return compare(root.left,root.right);
}
static boolean compare(TreeNode left,TreeNode right){
if(right==null && left==null)return true;
else if(right==null || left==null)return false;
else if(right!=null && left!=null && left.val!=right.val)return false;
return compare(left.left,right.right)&&compare(left.right,right.left);
}
}
7.13完全二叉树节点的个数
class Solution {
public int countNodes(TreeNode root) {
//根据完全二叉树进行改进
if(root==null)return 0;
TreeNode left=root;
TreeNode right=root;
int lc=0,rc=0;
while(left!=null){
left=left.left;
lc++;
}
while(right!=null){
right=right.right;
rc++;
}
if(lc==rc)return (int)Math.pow(2,lc)-1;
return countNodes(root.left)+countNodes(root.right)+1;
}
}
7.14平衡二叉树
class Solution {
static boolean ans;
public boolean isBalanced(TreeNode root) {
ans=true;
dfs(root);
return ans;
}
static int dfs(TreeNode root){
if(root==null)return 0;
int l=dfs(root.left);
int r=dfs(root.right);
if(Math.abs(l-r)>1)ans=false;
return Math.max(l,r)+1;
}
}
7.15二叉树的所有路径
class Solution {
List<String> path=new ArrayList<>();
static List<String> ans=new ArrayList<>();
public List<String> binaryTreePaths(TreeNode root) {
ans.clear();
if(root==null)return ans;
dfs(root,""+root.val);
return ans;
}
public static void dfs(TreeNode root,String s){
//1.递归终止条件,到达叶节点
if(root.left==null && root.right==null){
ans.add(s);
return;
}
//单层逻辑
if(root.left!=null)dfs(root.left,s+"->"+root.left.val);
if(root.right!=null)dfs(root.right,s+"->"+root.right.val);
}
}
思路分析
- 这里特别像字母的排列组合,所以我们可以使用回溯算法解决
- 其次就是他要求从根节点到叶子节点,我们很容易想到深搜
- 终止条件:到达叶子节点,将当前路径加入答案
- 单层逻辑:先判断当前节点,而后向下遍历
7.16二叉树左叶子的和
分析
- 左叶子:是父节点的左儿子,且没有左右子节点的节点
- 遍历:找出符合要求的相加即可
class Solution {
static int sum=0;
public int sumOfLeftLeaves(TreeNode root) {
sum=0;
dfs(root);
return sum;
}
//对整棵树进行遍历,将符合要求的节点的值相加
public static void dfs(TreeNode root){
if(root==null)return;
if(root.left!=null && (root.left.left==null && root.left.right==null)){
sum=sum+root.left.val;
}
dfs(root.left);
dfs(root.right);
}
}
7.17找树左下角的值
思路分析
层序遍历选择最后一层的第一个值
class Solution {
List<List<Integer>> ans=new ArrayList<>();
public int findBottomLeftValue(TreeNode root) {
if(root==null)return 0;
Deque<TreeNode> q=new ArrayDeque<>();
q.offer(root);
while(!q.isEmpty()){
List<Integer> level=new ArrayList<>();
int size=q.size();
for(int i=0;i<size;i++){
TreeNode t=q.poll();
level.add(t.val);
if(t.left!=null)q.offer(t.left);
if(t.right!=null)q.offer(t.right);
}
ans.add(level);
}
return ans.get(ans.size()-1).get(0);
}
}
7.18 路径总和
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root==null)return false;
targetSum=targetSum-root.val;
if(root.left==null && root.right==null)return targetSum==0;
return (root.left!=null && hasPathSum(root.left,targetSum)) ||
(root.right!=null && hasPathSum(root.right,targetSum));
}
}
7.19从中序后序序列构造二叉树
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
TreeNode root=buildTree(inorder,0,inorder.length-1,postorder,0,postorder.length-1);
return root;
}
public static TreeNode buildTree(int[] in ,int ins,int ine,int[] po,int pos,int poe){
//递归终止条件
if(pos>poe)return null;
//单层逻辑
int rootval=po[poe];
int index=0;//查找中序中根节点位置
for(int i=ins;i<=ine;i++){
if(in[i]==rootval){
index=i;
break;
}
}
TreeNode root=new TreeNode(rootval);
int leftsize=index-ins;//1
root.left=buildTree(in,ins,index-1,po,pos,pos+leftsize-1);
root.right=buildTree(in,index+1,ine,po,pos+leftsize,poe-1);
return root;
}
}
7.20最大二叉树
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
TreeNode root=build(nums,0,nums.length-1);
return root;
}
public static TreeNode build(int[] nums,int l,int r){
if(l>r)return null;
int max=nums[l],index=l;//记录当前数组的最大值及序号
//寻找最大值及其序号
for(int i=l;i<=r;i++){
if(nums[i]>max){
max=nums[i];
index=i;
}
}
TreeNode root=new TreeNode(max);
root.left=build(nums,l,index-1);
root.right=build(nums,index+1,r);
return root;
}
}
7.21合并二叉树
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
return dfs(root1,root2);
}
public TreeNode dfs(TreeNode root1,TreeNode root2){
//递归终止条件
if(root1==null)return root2;
if(root2==null)return root1;
root1.val+=root2.val;
root1.left=dfs(root1.left,root2.left);
root1.right=dfs(root1.right,root2.right);
return root1;
}
}
7.22BST中的搜索
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
//递归终止条件
if(root==null)return null;
//单层逻辑
if(root.val==val)return root;
else if(val<root.val)return searchBST(root.left,val);
else return searchBST(root.right,val);
}
}
7.23验证二叉搜索树**
class Solution {
//使用中序遍历进行操作
private static long pre;
public boolean isValidBST(TreeNode root) {
pre=Long.MIN_VALUE;
return check(root);
}
public static boolean check(TreeNode root){
if(root==null)return true;
if(!check(root.left))return false;
if(root.val<=pre)return false;
pre=root.val;
return check(root.right);
}
}
7.24二叉搜索树的绝对差
class Solution {
public static List<Integer> ans=new ArrayList<>();
public int getMinimumDifference(TreeNode root) {
ans.clear();
dfs(root);
int min=0x3f3f3f3f;
for(int i=1;i<ans.size();i++){
min=Math.min(min,ans.get(i)-ans.get(i-1));
}
return min;
}
public static void dfs(TreeNode root){
if(root==null)return;
dfs(root.left);
ans.add(root.val);
dfs(root.right);
}
}
7.25二叉搜索树中的众数**
class Solution {
//中序遍历等同于遍历一个有序数组
static List<Integer> ans=new ArrayList<>();
static int maxc=0;//记录最大长度
static int curc=0;//记录当前遍历数的长度
static int last;//记录上一个值
public int[] findMode(TreeNode root) {
ans.clear();
maxc=0;
curc=0;
last=root.val;
dfs(root);
return ans.stream().mapToInt(Integer::intValue).toArray();
}
public static void dfs(TreeNode root){
if(root==null)return;
dfs(root.left);
if(curc==0 || root.val==last){//curc为0(特判),当前值与上一个相等
last=root.val;
curc++;
}else{
last=root.val;
curc=1;
}
//长度大于目前最大长度
if(curc>maxc){
//更新以前的数
ans.clear();
maxc=curc;
ans.add(last);
}else if(curc==maxc){
ans.add(last);
}
dfs(root.right);
}
}
7.26二叉搜索树中最近公共祖先
lass Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
return dfs(root,q,p);
}
public static TreeNode dfs(TreeNode root,TreeNode p,TreeNode q){
//递归终止条件
if(root==null || root==p || root==q)return root;
TreeNode left=dfs(root.left,p,q);
TreeNode right=dfs(root.right,p,q);
//三种情况判断
if(left!=null && right!=null)return root;
if(left==null)return right;
return left;
}
}
7.27二叉搜索树的插入
//找到符合要求的叶子节点插入
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if(root==null)return new TreeNode(val);
if(root.val>val)root.left=insertIntoBST(root.left,val);
else root.right=insertIntoBST(root.right,val);
return root;
}
}
7.28二叉搜索树的删除**
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if(root==null)return root;
if(root.val==key){
if(root.left==null){//叶子节点
return root.right;
}else if(root.right==null){
return root.left;
}else{//左右都不为空
//找到右子树最左边的节点
TreeNode cur=root.right;
while(cur.left!=null){
cur=cur.left;
}
cur.left=root.left;
root=root.right;
return root;
}
}
if(root.val>key)root.left=deleteNode(root.left,key);
else root.right=deleteNode(root.right,key);
return root;
}
}
7.29修剪二叉搜索树**
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
if(root==null)return null;
if(root.val<low)return trimBST(root.right,low,high);
if(root.val>high)return trimBST(root.left,low,high);
root.left=trimBST(root.left,low,high);
root.right=trimBST(root.right,low,high);
return root;
}
}
7.30将有序数组转换为二叉搜索树
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return build(nums,0,nums.length-1);
}
public static TreeNode build(int[] nums,int l,int r){
if(l>r)return null;
int mid=l+r>>1;
TreeNode root=new TreeNode(nums[mid]);
root.left=build(nums,l,mid-1);
root.right=build(nums,mid+1,r);
return root;
}
}
7.31 将二叉搜索树转换为累加树
class Solution {
public static int sum;
public TreeNode convertBST(TreeNode root) {
sum=0;
dfs(root);
return root;
}
public static void dfs(TreeNode root){
if(root==null)return;
dfs(root.right);
sum=sum+root.val;
root.val=sum;
dfs(root.left);
}
}
8.回溯算法
8.0算法总结
组合问题
-
N个数里面按一定规则出k个数的集合
-
题目:1,2,3,4,5
-
代码模板
void backtracking(参数) { //参数:start(遍历开始未知),u(遍历到第几位),tar(目标值),其他数 if (终止条件) { 存放结果; return; } for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) { 处理节点; backtracking(路径,选择列表); // 递归 回溯,撤销处理结果 } }
-
类型总结
- 从同一个集合中有放回的抽取(可重复使用一个数字)[4]
- 从同一个集合中无放回的抽取(每个数字使用一次):[1,2,5]
- 从多个集合中每个选取一个进行组合:[3]
-
技巧总结
- 类型1,2:一般有start(从那个位置遍历,该参数实际上也有去重功能),1取同位置(i),2取下一个位置 (i+1)
- 类型3:不需要start,因为多个集合*取组合,各个集合之间相互不影响
- 求和问题:先排序,后爆搜
- 去重(组合总和II)
同层去重:candidates[i] == candidates[i - 1] && used[i - 1] == false
(前一个树枝使用过该数)
树枝去重:candidates[i] == candidates[i - 1] && used[i - 1] == true
(同一树枝的前面节点使用过)
-
分割问题
-
子集问题
-
排列问题
-
棋盘问题
8.1组合问题
class Solution {
public static List<Integer> path=new ArrayList<>();
public static List<List<Integer>> ans=new ArrayList<>();
public static int k,n;
public List<List<Integer>> combine(int n, int k) {
ans.clear();
path.clear();
this.n=n;
this.k=k;
dfs(0,1);
return ans;
}
public static void dfs(int p,int start){//startfor循环起始位置
//递归终止条件
if(p==k){
List<Integer> tmp=new ArrayList<>(path);
ans.add(tmp);
return;
}
//单层逻辑
for(int i=start;i<=n;i++){
path.add(i);
dfs(p+1,i+1);//为了保证不重复下此遍历重i+1开始
path.remove(path.size()-1);
}
}
}
8.2组合总和III
class Solution {
static List<Integer> path=new ArrayList<>();
static List<List<Integer>> ans=new ArrayList<>();
public List<List<Integer>> combinationSum3(int k, int n) {
path.clear();
ans.clear();
dfs(1,n,k);
return ans;
}
public static void dfs(int start,int n,int k){
if(n==0){//和达到要求
if(k==0)ans.add(new ArrayList<>(path));
return;
}
for(int i=start;i<=9;i++){
if(n>=i){
path.add(i);
dfs(i+1,n-i,k-1);//k--为什么是错的
path.remove(path.size()-1);
}
}
}
}
8.3电话号码的组合
class Solution {
static List<String> ans=new ArrayList<>();
static String[] strs={
"","","abc","def",
"ghi","jkl","mno",
"pqrs","tuv","wxyz"
};
public List<String> letterCombinations(String digits) {
ans.clear();
if(digits.isEmpty())return ans;
dfs(digits,0,"");
return ans;
}
static void dfs(String digits,int u ,String path){//遍历到第几位了
if(u==digits.length()){
ans.add(path);//并非使用全局变量记录,所以不需要从新构造
return;
}
char[] chs=strs[digits.charAt(u)-'0'].toCharArray();
for(char c:chs){
dfs(digits,u+1,path+c);//这里传的是一个参数所以不需要恢复现场
}
}
}
8.4 组合总和
class Solution {
public static List<List<Integer>> ans=new ArrayList<>();
public static List<Integer> path=new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
path.clear();
ans.clear();
Arrays.sort(candidates);
dfs(candidates,target,0);
return ans;
}
public static void dfs(int[] can,int target,int start){
if(target<0)return;
if(target==0){
ans.add(new ArrayList<>(path));//符合要求的加入集合
return;
}
for(int i=start;i<can.length;i++){
path.add(can[i]);
dfs(can,target-can[i],i);//不用下一个,取这一个即可
path.remove(path.size()-1);
}
}
}
8.5组合总和II
class Solution {
public static List<Integer> path=new ArrayList<>();
public static List<List<Integer>> ans=new ArrayList<>();
public static boolean[] st=new boolean[110];
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
path.clear();
ans.clear();
Arrays.sort(candidates);
dfs(0,target,candidates);
return ans;
}
public static void dfs(int start,int target ,int[] can){
if(target==0){
ans.add(new ArrayList<>(path));
return;
}
for(int i=start;i<can.length;i++){
if(i!=0 && can[i]==can[i-1] && st[i-1]==false)continue;
if(target>=can[i]){
path.add(can[i]);
st[i]=true;
dfs(i+1,target-can[i],can);
st[i]=false;
path.remove(path.size()-1);
}
}
}
}
9.贪心算法
10.动态规划
10.1斐波那契数
class Solution {
public int fib(int n) {
if(n==1)return 1;
if(n==0)return 0;
int a=0,b=1,c=0;
for(int i=2;i<=n;i++){
c=a+b;
a=b;
b=c;
}
return c;
}
}
10.2爬楼梯
class Solution {
public int climbStairs(int n) {
if(n<=2)return n;
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];
}
}
10.3使用最小花费爬楼梯
class Solution {
public int minCostClimbingStairs(int[] cost) {
int n=cost.length;
int[] dp=new int[n+1];
dp[0]=0;
dp[1]=0;//可以选择从1阶或2阶爬
for(int i=2;i<=n;i++){
dp[i]=Math.min(dp[i-2]+cost[i-2],dp[i-1]+cost[i-1]);
}
return dp[n];
}
}
10.4不同路径
class Solution {
public int uniquePaths(int m, int n) {
if(n<=1 || m<=1)return 1;
int[][] dp=new int[n][m];
//值得初始化
for(int i=1;i<m;i++)dp[0][i]=1;
for(int i=1;i<n;i++)dp[i][0]=1;
for(int i=1;i<n;i++){
for(int j=1;j<m;j++)dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
return dp[n-1][m-1];
}
}
10.5 不同路径II
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int rs=obstacleGrid.length;
int cs=obstacleGrid[0].length;
int[][] dp=new int[rs][cs];
//值得初始化
for(int i=0;i<rs;i++){
if(obstacleGrid[i][0]==0){
dp[i][0]=1;
}else{
break;
}
}
for(int i=0;i<cs;i++){
if(obstacleGrid[0][i]==0){
dp[0][i]=1;
}else{
break;
}
}
for(int i=1;i<rs;i++){
for(int j=1;j<cs;j++){
if(obstacleGrid[i][j]==0){
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
}
return dp[rs-1][cs-1];
}
}
10.6不同得二叉搜索树
class Solution {
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];
}
}