380. 常数时间插入、删除和获取随机元素
//O(1)时间可以插入元素:动态数组Arraylist,哈希表hashmap。但是哈希表没法用O(1)实现随机返回元素和删除元素。可以O(1)获得元素,想到动态数组。所以把哈希表和动态数组结合。对于删除元素,把要删除的元素和动态数组中最后一个元素交换位置,然后删除最后元素即可。哈希表中把索引作为值,键是要插入的数字。
import java.util.Random;
class RandomizedSet {
List list;
Map hm;
Random rand=new Random();
/** Initialize your data structure here. */
public RandomizedSet() {
list=new ArrayList();
hm=new HashMap<>();
}
/** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
public boolean insert(int val) {
if(hm.containsKey(val)) return false;
//插入元素:
hm.put(val,list.size());
list.add(val);
return true;
}
/** Removes a value from the set. Returns true if the set contained the specified element. */
public boolean remove(int val) {
if(!hm.containsKey(val)) return false;
//删除元素
//获得最后一个元素
int last=list.get(list.size()-1);
//获得被删除元素的索引:
int index=hm.get(val);
//交换位置,即在arraylist中把最后一个元素放在被删除元素的位置:
list.set(index,last);
list.remove(list.size()-1);
hm.put(last,index); //可被覆盖掉
hm.remove(val);
return true;
}
/** Get a random element from the set. */
public int getRandom() {
int i=rand.nextInt(list.size());
int val=list.get(i);
return val;
}
}
/**
* Your RandomizedSet object will be instantiated and called as such:
* RandomizedSet obj = new RandomizedSet();
* boolean param_1 = obj.insert(val);
* boolean param_2 = obj.remove(val);
* int param_3 = obj.getRandom();
*/
710. 黑名单中的随机数
//动态数组+hashmap
//注意:这里用的是hashset而不是arraylist的原因是:
//在remove的时候,可能会出现一种情况:N=2, blacklist=[1],如果list.remove(1)会判下标越界,因为arraylist.remove()参数可以是Index可以是val(此时想删1这个数字,系统会以为1是index而出现越界),而Hashset移除元素就是val,所以不会越界。
class Solution {
Map hm;
Set list;
int whitelist;
public Solution(int N, int[] blacklist) {
hm=new HashMap<>();
list=new HashSet<>();
//获得白名单长度。目的是:[0,whitelist)中都是白名单。需要把这个范围中的黑名单映射到[whitelist,N)中的白名单。
whitelist=N-blacklist.length;
for(int i=whitelist;i it=list.iterator();
for(int i=0;i
26.删除排序数组中的重复项
//一:原地删除:一想到的方法有:交换待删除的元素和数组中最后一个元素位置然后删除最后一个。第二个就是双指针快慢指针。
class Solution {
public int removeDuplicates(int[] nums) {
if(nums==null)
return 0;
int slow=0,fast=0;
while(fast
27.移除元素
//一:想到的方法:交换元素到最后,但是要注意如果待删除的元素数字在最后要做个判断
//实现的时候各种小问题,后来看了解答。
class Solution {
public int removeElement(int[] nums, int val) {
if(nums==null || nums.length==0)
return 0;
//想到的方法:交换元素到最后,但是要注意如果待删除的元素数字在最后要做个判断
int left=0,right=nums.length-1;
int len=nums.length;
while(left<=right){
if(nums[left]==val){
while(nums[right]==val && right>left ){
right--;
len--;
}
//注意这个If判断!!如果left和right都指在了同一个位置
if(nums[right]!=val){
int temp=nums[left];
nums[left]=nums[right];
nums[right]=temp;
right--;
}
len--;
}
left++;
}
return len;
}
}
//二:快慢指针
class Solution {
public int removeElement(int[] nums, int val) {
if(nums==null || nums.length==0)
return 0;
//双指针:快慢指针
int slow=0,fast=0;
for(;fast
83.删除排序链表中的重复元素
//双指针:同理,快慢指针
/**
* 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 deleteDuplicates(ListNode head) {
if(head==null)
return head;
//双指针:同理,快慢指针
ListNode slow=head,fast=head;
while(fast.next!=null){
if(fast.next.val!=slow.val){
slow.next=fast.next;
slow=fast.next;
}
fast=fast.next;
}
slow.next=null;
return head;
}
}
283.移动零
//要保证相对顺序,所以用快慢指针
class Solution {
public void moveZeroes(int[] nums) {
int slow=0,fast=0;
for(;fast
316 题「去除重复字母」
//用栈
class Solution {
public String removeDuplicateLetters(String s) {
Stack stack=new Stack<>();
boolean[] flag=new boolean[26];
int[] count=new int[26];
//初始化flag=false,然后再计数
for(int i=0;is.charAt(i)){
if(count[stack.peek()-'a']!=0){
char c=stack.pop();
flag[c-'a']=false;
}
else{
break;
}
}
flag[index]=true;
stack.push(s.charAt(i));
//count[index]--;
}
count[index]--;
}
StringBuilder sb=new StringBuilder();
while(!stack.isEmpty()){
sb.append(stack.pop());
}
return sb.reverse().toString();
}
}
1081 题「不同字符的最小子序列」
//和316题完全一个意思
class Solution {
public String smallestSubsequence(String s) {
Stack stack=new Stack<>();
boolean[] flag=new boolean[26];
int[] count=new int[26];
for(int i=0;is.charAt(i)){
char top=stack.peek();
if(count[top-'a']!=0){
stack.pop();
flag[top-'a']=false;
}
else
break;
}
flag[index]=true;
stack.push(s.charAt(i));
}
count[index]--;
}
StringBuilder sb=new StringBuilder();
while(!stack.isEmpty()){
sb.append(stack.pop());
}
return sb.reverse().toString();
}
}
单调栈实际上就是栈,只是利用了一些巧妙的逻辑,使得每次新元素入栈后,栈内的元素都保持有序(单调递增或单调递减)。
模板:
int res=0;
Stack stack=new Stack<>();
//如果希望栈中所有数据出栈,需要做一些其他操作,比如给数组最后添加一个数。或者给数组前后都添加一个数。
//注意:需要入栈的是索引呢还是值呢,根据题目来选择
for (遍历这个数组)
{
while (!stack.isEmpty() && 栈顶元素和当前元素比较)
{
stack.pop(); //注意:需要判断这个元素需不需要保存,如果需要定义一个变量存储它
更新结果res;
}
stack.push();
}
496. 下一个更大元素 I
//一:暴力
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
int[] res=new int[nums1.length];
int flag=0;
for(int i=0;inums2[j+1] ){
j++;
}
if(j==nums2.length-1){
if(nums2[j]<=nums2[index]) res[flag++]=-1;
else if(nums2[j]>nums2[index]) res[flag++]=nums2[j];
break;
}
else{
res[flag++]=nums2[j+1];
break;
}
}
}
return res;
}
}
//二:单调栈
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
//单调栈,先只看nums2,再用一个hashmap维护每个元素对应的下一个最大元素,最后根据这个哈希表遍历Nums1
Map hs=new HashMap<>();
Stack stack=new Stack<>();
for(int i=0;istack.peek()){
int temp=stack.pop();
hs.put(temp,nums2[i]);
}
stack.push(nums2[i]);
}
while(!stack.isEmpty()){
hs.put(stack.pop(),-1);
}
//获得结果
int[] res=new int[nums1.length];
for(int i=0;i
503. 下一个更大元素 II
//一:顺序遍历,单调栈。本来一开始也想用hashmap,但是不行。因为比如当前1的下一个最大元素是3,之后另一个1最大元素是5,hs中key不能重复。
//关键:stack中不存数字,存索引! 循环数组 index%length
class Solution {
public int[] nextGreaterElements(int[] nums) {
if(nums==null || nums.length==0)
return new int[]{};
//循环数组,把可比较的长度变成当前长度的2倍
int[] res=new int[nums.length];
Arrays.fill(res,-1);
Stack stack=new Stack<>();
int len=2*nums.length;
int index=0;
for(int i=0;inums[stack.peek()]){
res[stack.pop()]=nums[i%nums.length];
}
stack.push(i%nums.length);
}
return res;
}
}
//二:逆序。官方题解是逆序,不太想的明白。有时间记得再写一下吧。
739.每日温度
//单调栈,栈中存的是下一个更高温度的索引
//和503一样
class Solution {
public int[] dailyTemperatures(int[] T) {
int[] res=new int[T.length];
Arrays.fill(res,0);
int index=0;
Stack stack=new Stack<>();
for(int i=0;iT[stack.peek()]){
res[stack.peek()]=i-stack.peek();
stack.pop();
}
stack.push(i);
}
return res;
}
}
84. 柱状图中最大的矩形
//先暴力.思路是两个指针,一个往左,一个往右,找到连续的小于等于当前元素的
//但结果会超出时间限制,只能通过91/96个用例。暴力不太行。
class Solution {
public int largestRectangleArea(int[] heights) {
int res=0;
for(int i=0;i=0 && heights[left-1]>=heights[i]){
left--;
}
while(right+1=heights[i]){
right++;
}
int temp=(right-left+1)*heights[i];
if(res stack=new Stack<>();
for(int i=0;i
42. 接雨水
//单调栈。比当前栈顶元素小,那么就入栈。否则的话,开始找边界计算面积了。
//综合来看,是个单调递减栈
//栈内还是存索引,方便计算左右边界
class Solution {
public int trap(int[] height) {
int res=0;
Stack stack=new Stack<>();
for(int i=0;iheight[stack.peek()]){
int temp=stack.pop();
if(stack.isEmpty()) break;
//寻找左右边界。
int left=stack.peek();
int right=i;
int h=Math.min(height[left],height[right])-height[temp];
res+=h*(right-left-1);
}
stack.push(i);
}
return res;
}
}
模板:
模板:
//如果一个字符进入窗口,应该增加window计数器;如果一个字符将移出窗口的时候,应该减少window计数器;当valid满足need时应该收缩窗口;应该在收缩窗口的时候更新最终结果。
public String minWindow(String s, String t) {
HashMap need=new HashMap<>();
HashMap window=new HashMap<>();
for(int i=0;i
76.最小覆盖子串
class Solution {
//如果一个字符进入窗口,应该增加window计数器;如果一个字符将移出窗口的时候,应该减少window计数器;当valid满足need时应该收缩窗口;应该在收缩窗口的时候更新最终结果。
public String minWindow(String s, String t) {
HashMap need=new HashMap<>();
HashMap window=new HashMap<>();
for(int i=0;i
3.无重复字符的最长子串
//一:滑动窗口,注意判断窗口要左移时候怎么做的
//思路有但是代码总有问题,最后参考了别人的答案。
class Solution {
public int lengthOfLongestSubstring(String s) {
//滑动窗口
int left=0,right=0;
int len=0;
HashMap window=new HashMap<>();
while(right1){
char lefttemp=s.charAt(left);
left++;
window.put(lefttemp,window.getOrDefault(lefttemp,0)-1);
}
if(len
438. 找到字符串中所有字母异位词
class Solution {
public List findAnagrams(String s, String p) {
//滑动窗口
List res=new ArrayList<>();
HashMap need=new HashMap<>();
HashMap window=new HashMap<>();
int left=0,right=0;
int value=0;
for(int i=0;i=p.length()){
if(value==need.size()) res.add(left);
char lefttemp=s.charAt(left);
left++;
if(need.containsKey(lefttemp)){
if(need.get(lefttemp).equals(window.get(lefttemp)))
value--;
window.put(lefttemp,window.getOrDefault(lefttemp,0)-1);
}
}
}
return res;
}
}
567.字符串的排列
class Solution {
public boolean checkInclusion(String s1, String s2) {
//这个题和438一个意思,用滑动窗口
HashMap window=new HashMap<>();
HashMap need=new HashMap<>();
//记录 满足条件的字符数
int valid=0;
int left=0,right=0;
for(int i=0;i=s1.length()){
if(need.size()==valid) return true;
char lefttemp=s2.charAt(left);
left++;
if(need.containsKey(lefttemp)){
if(need.get(lefttemp).equals(window.get(lefttemp))){
valid--;
}
window.put(lefttemp,window.getOrDefault(lefttemp,0)-1);
}
}
}
return false;
}
}
226. 翻转二叉树
/**
* 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 TreeNode invertTree(TreeNode root) {
if(root==null) return null;
//相当于一个前序遍历
//交换两个节点的值
TreeNode tmp=root.left;
root.left=root.right;
root.right=tmp;
invertTree(root.left);
invertTree(root.right);
return root;
}
}
//二:用后序遍历
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root==null) return null;
invertTree(root.left);
invertTree(root.right);
TreeNode tmp=root.left;
root.left=root.right;
root.right=tmp;
return root;
}
}
//中序不可以,因为中序是左根右,到根的时候交换左右节点,再遍历右的时候相当于把交换过来的左边的再进行一次操作。最终会导致左边节点交换了两次,右边不变。想要解决这个问题,可以翻转两次左边的树。
//三:中序遍历
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root==null) return null;
invertTree(root.left);
TreeNode tmp=root.left;
root.left=root.right;
root.right=tmp;
//注意:这里还是left
invertTree(root.left);
return root;
}
}
116. 填充二叉树节点的右侧指针
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node next;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, Node _left, Node _right, Node _next) {
val = _val;
left = _left;
right = _right;
next = _next;
}
};
*/
//一:递归
//二叉树的问题难点重点:如何把题目的要求细化成每个节点需要做的事情
//简单的按照前序递归不行,因为没办法连接到在同一层但不是同一个父节点的两个节点。
//所以现在把每个节点做的事细化成:将每两个相邻节点连接起来
class Solution {
public Node connect(Node root) {
if(root==null) return null;
connectTwoNode(root.left,root.right);
return root;
}
public void connectTwoNode(Node node1,Node node2){
if(node1==null || node2==null) return;
node1.next=node2;
//递归的每两个进行连接
connectTwoNode(node1.left,node1.right);
connectTwoNode(node2.left,node2.right);
//继续连接不是同一个父节点但是在同一层且相邻的节点
connectTwoNode(node1.right,node2.left);
}
}
//二:不满足常量级的一个方法,学一下思路。使用层次遍历,然后用一个队列把每一层节点存好,然后进行连接。
//用linkedlist,它继承了queue的接口(ArrayList没有继承queue接口).
//注意,不能直接用queue,它和栈不一样,java api里queue是一个接口,stack是个类。
class Solution {
public Node connect(Node root) {
if(root==null) return null;
Queue queue=new LinkedList<>();
queue.offer(root);
while(queue.size()>0){
int len=queue.size();
for(int i=0;i
114. 将二叉树展开为链表
/**
* 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 {
Queue queue=new LinkedList<>();
public void flatten(TreeNode root) {
if(root==null) return;
//先序遍历存节点,然后再构建一个新的
FirstTraverse(root);
if(queue.size()==1) return;
TreeNode cur=root;
while(queue.size()>0){
cur.right=queue.remove();
cur.left=null;
cur=cur.right;
}
return;
}
public void FirstTraverse(TreeNode root){
if(root==null) return;
queue.offer(root);
FirstTraverse(root.left);
FirstTraverse(root.right);
}
}
//二:递归,没写出来。看了别人的答案。
class Solution {
public void flatten(TreeNode root) {
if(root==null) return;
flatten(root.left);
flatten(root.right);
TreeNode left=root.left;
TreeNode right=root.right;
root.left=null;
root.right=left;
TreeNode p=root;
while(p.right!=null){
p=p.right;
}
p.right=right;
return;
}
}
654.最大二叉树
/**
* 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 TreeNode constructMaximumBinaryTree(int[] nums) {
return build(nums,0,nums.length-1);
}
public TreeNode build(int[] nums,int left,int right){
if(left>right) return null;
int max=-1;
int index=-1;
for(int i=left;i<=right;i++){
if(nums[i]>max){
max=nums[i];
index=i;
}
}
TreeNode root=new TreeNode(max);
root.left=build(nums,left,index-1);
root.right=build(nums,index+1,right);
return root;
}
}
105.从前序与中序遍历序列构造二叉树
/**
* 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 TreeNode buildTree(int[] preorder, int[] inorder) {
//根据前序遍历的第一个 ,找到其在中序遍历的位置。然后该点左边是其左子树节点,右边是其右子树节点。
return build(preorder,0,preorder.length-1,inorder,0,inorder.length-1);
}
public TreeNode build(int[] preorder,int preStart,int preEnd,int[] inorder,int inStart,int inEnd){
if(preStart>preEnd) return null;
int rootval=preorder[preStart];
int index=-1;
for(int i=inStart;i<=inEnd;i++){
if(inorder[i]==rootval){
index=i;
break;
}
}
//rootval是根节点的值
TreeNode root=new TreeNode(rootval);
root.left=build(preorder,preStart+1,preStart+index-inStart,inorder,inStart,index-1);
root.right=build(preorder,preStart+index-inStart+1,preEnd,inorder,index+1,inEnd);
return root;
}
}
//对于一的优化:由于每次是遍历一遍inorder数组然后找到对应的索引下标。由于树中没有重复的元素,可以直接用hashmap把索引下标存起来。
class Solution {
Map map;
public TreeNode buildTree(int[] preorder, int[] inorder) {
map=new HashMap<>();
for(int i=0;ipreEnd) return null;
int rootval=preorder[preStart];
int index=map.get(rootval);
//rootval是根节点的值
TreeNode root=new TreeNode(rootval);
root.left=build(preorder,preStart+1,preStart+index-inStart,inorder,inStart,index-1);
root.right=build(preorder,preStart+index-inStart+1,preEnd,inorder,index+1,inEnd);
return root;
}
}
//二:看别人的题解还有迭代法,没看明白。有时间再看。
106.从中序与后序遍历序列构造二叉树
/**
* 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 TreeNode buildTree(int[] inorder, int[] postorder) {
//区间是左右都闭合。
//根节点是后序的最后一个。
return build(inorder,0,inorder.length-1,postorder,0,postorder.length-1);
}
public TreeNode build(int[] inorder,int inStart,int inEnd,int[] postorder,int postStart,int postEnd){
if(postStart>postEnd) return null;
int rootval=postorder[postEnd];
int index=-1;
for(int i=inStart;i<=inEnd;i++){
if(inorder[i]==rootval){
index=i;
break;
}
}
TreeNode root=new TreeNode(rootval);
root.left=build(inorder,inStart,index-1,postorder,postStart,postStart+index-inStart-1);
root.right=build(inorder,index+1,inEnd,postorder,postStart+index-inStart,postEnd-1);
return root;
}
}
652.寻找重复子树
/**
* 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;
* }
* }
*/
//本来的思路是:哈希表存,key是节点,值是节点先序遍历得到的字符串。然后比较值,res存结果。
//但是对于如果得到每个节点及其先序遍历的字符串没想出来,看了别人的解答得到了一点启发:存序列化的二叉树。
//注意,res存的节点是地址。所以可能会出现res中结果重复。所以最开始的思路不行。哈希表的键改成string,值改成其出现的次数。
//重点难点:如何把二叉树序列化
class Solution {
Map map=new HashMap<>();
List res=new ArrayList<>();
public List findDuplicateSubtrees(TreeNode root) {
//哈希表存,key是节点,值是节点先序遍历得到的字符串,res存结果
traverse(root);
return res;
}
public String traverse(TreeNode root){
if(root==null) return "#";
String left=traverse(root.left);
String right=traverse(root.right);
String tmp=left+","+right+","+root.val;
if(map.containsKey(tmp)){
int val=map.get(tmp);
if(val==1)
res.add(root);
}
map.put(tmp,map.getOrDefault(tmp,0)+1);
return tmp;
}
}
230. BST第K小的元素
//一:二叉搜索树特性,可以知道其中序遍历是升序的。所以可以用中序遍历走一遍,然后再找第k小的结果;
class Solution {
List list=new ArrayList<>();
public int kthSmallest(TreeNode root, int k) {
traverse(root);
int val=list.get(k-1);
return val;
}
public void traverse(TreeNode root){
if(root==null) return;
traverse(root.left);
list.add(root.val);
traverse(root.right);
return;
}
}
//基于一的改进:这种方法最坏情况下时间复杂度是O(N),就是二叉树每个节点都访问过一遍了。
//如果想要达到对数级别复杂度的方法,需要改进二叉搜索树的结构,让其多维护一个信息,即每个节点的左孩子个数。
class Solution {
int index=0;
int res=-1;
public int kthSmallest(TreeNode root, int k) {
traverse(root,k);
return res;
}
public void traverse(TreeNode root,int k){
if(root==null) return;
traverse(root.left,k);
index++;
if(index==k){
res=root.val;
return;
}
traverse(root.right,k);
return;
}
}
//二:分治法。其本质就是多计算一个每个节点的左孩子个数,然后和K比较。
class Solution {
int res=-1;
public int kthSmallest(TreeNode root, int k) {
int left=count(root.left);
if(left+1==k)
return root.val;
else if(left+1>k){
res=kthSmallest(root.left,k);
}
else
res=kthSmallest(root.right,k-left-1);
return res;
}
public int count(TreeNode root){
if(root==null) return 0;
int left=count(root.left);
int right=count(root.right);
return (left+right+1);
}
}
538. 二叉搜索树转化累加树
/**
* 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;
* }
* }
*/
//BST相关的问题常见思路:BST 左小右大的特性提升算法效率/利用中序遍历的特性满足题目的要求
//本题用中序遍历,让其降序排列,就是右中左
class Solution {
int sum=0;
public TreeNode convertBST(TreeNode root) {
if(root==null) return null;
convert(root);
return root;
}
//注意这个逆序降序怎么打印的!写的时候脑子浆糊了半天递归不出来。
public void convert(TreeNode root){
if(root==null) return;
convert(root.right);
//真正累加的关键
sum+=root.val;
convert(root.left);
return;
}
}
450. 删除二叉搜索树中的节点
/**
* 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 TreeNode deleteNode(TreeNode root, int key) {
if(root==null) return null;
if(root.valkey){
root.left=deleteNode(root.left,key);
}
else if(root.val==key){
if(root.left==null && root.right==null){
return null;
}
else if(root.left==null || root.right==null){
if(root.left==null)
return root.right;
else
return root.left;
}
//注意这里怎么写的!!!!!一直没想出来!!!!
//找到待删节点右子树的最小节点,待删节点的左子树一定比最小节点小,所以直接把其左子树放到最小节点的左子树,返回带删节点的右子树就行。
else if(root.left!=null && root.right!=null){
TreeNode node=root.right;
while(node.left!=null){
node=node.left;
}
node.left=root.left;
return root.right;
}
}
return root;
}
}
701.二叉搜索树中的插入操作
/**
* 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 TreeNode insertIntoBST(TreeNode root, int val) {
if(root==null){
return new TreeNode(val);
}
if(root.val>val){
root.left=insertIntoBST(root.left,val);
}
else if(root.val
700.二叉搜索树中的搜索
/**
* 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 TreeNode searchBST(TreeNode root, int val) {
if(root==null) return null;
if(root.val==val){
return root;
}
else if(root.val>val)
return searchBST(root.left,val);
else
return searchBST(root.right,val);
}
}
//二:迭代
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if(root==null) return null;
while(root!=null){
if(root.val==val){
return root;
}
else if(root.val>val){
root=root.left;
}
else if(root.val
98.验证二叉搜索树(Medium)
/**
* 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 {
List ls=new ArrayList<>();
public boolean isValidBST(TreeNode root) {
traverse(root);
for(int i=0;i=ls.get(i+1))
return false;
}
}
return true;
}
public void traverse(TreeNode root){
if(root==null) return;
traverse(root.left);
ls.add(root.val);
traverse(root.right);
return;
}
}
//同样利用中序遍历的性质,但是比上一个优化,这里多记录一个上一个数字,pre
class Solution {
long pre = Long.MIN_VALUE;
public boolean isValidBST(TreeNode root) {
if(root==null) return true;
if(!isValidBST(root.left))
return false;
if(pre>=root.val) return false;
pre=root.val;
return isValidBST(root.right);
}
}
//二:递归,一个常见的思路是:通过使用辅助函数,增加函数参数列表,在参数中携带额外信息,将这种约束传递给子树的所有节点
class Solution {
public boolean isValidBST(TreeNode root) {
if(root==null || (root.left==null && root.right==null)) return true;
return traverse(root,null,null);
}
public boolean traverse(TreeNode root,TreeNode min,TreeNode max){
if(root==null) return true;
if(min!=null && min.val>=root.val) return false;
if(max!=null && max.val<=root.val) return false;
return traverse(root.left,min,root) && traverse(root.right,root,max);
}
}
297.二叉树的序列化与反序列化