【leetcode学习计划】数据结构入门(14 / 14)完结!

目录

1.两数之和

88.合并两个有序数组

350.两个数组的交集2

哈希表法

排序+双指针

121.买卖股票的最佳时机

贪心

动态规划

566.重塑矩阵

141.环形链表

快慢指针

21.合并两个有序链表

20.有效的括号

118.杨辉三角

36.有效的数独

73.矩阵置零

387.字符串的第一个唯一字符

383.赎金信

242.有效的字母异位词

203.移除链表元素

思路一:删除头结点时另加考虑

思路二:添加一个虚拟头结点 

思路三:递归

206.反转链表

思路一:迭代

思路二:递归 

83.删除排序链表中的重复元素

232.用栈实现队列

java法

c++法:

144.二叉树前序遍历

1、递归法

2、迭代法 

94、二叉树的中序遍历

1、递归法

2、迭代法

145.二叉树的后序遍历

1、递归法

2、迭代法 

102.二叉树的层序遍历

104.二叉树的最大深度

1、dfs

2、bfs 

101.对称二叉树

226.翻转二叉树

1、递归法

2、迭代法 

112.路径总和

1、用cur记录当前路径长度

2、直接用sum减去所经过的结点

700.二叉搜索树中的搜索

701.二叉搜索树的插入操作

98.验证二叉搜索树

1、递归

2、中序遍历判断二叉搜索树

653.两数之和4 - 输入二叉搜索树

235.二叉搜索树的最近公共祖先


53.最大子数组和

53. 最大子数组和

运用dp动态规划

如果前边累加后还不如自己本身大,那就把前边的都扔掉,从此自己本身重新开始累加

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int n=nums.size();
        vector<int>f(n+10);
        f[0]=nums[0];
        int res=nums[0];
        for(int i=1;i<n;i++)
        {
            f[i]=max(f[i-1]+nums[i],nums[i]);
            res=max(res,f[i]);
        }
        return res;
    }
};

1.两数之和

1. 两数之和

哈希表 存下标

如果哈希表中存在target-nums[i] 则输出 { 当前下标,target-nums[i]的下标 } 

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int n=nums.size();
        unordered_map<int,int>mp;
        for(int i=0;i<n;i++)
        {
            if(mp.count(target-nums[i])) return{i,mp[target-nums[i]]};
            mp[nums[i]]=i;
        }
        return {-1,-1};
    }
};

88.合并两个有序数组

88. 合并两个有序数组

经典归并排序 从后向前排 这样不会覆盖num1数组

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int l=m-1,r=n-1,k=m+n-1;
        while(l>=0&&r>=0)
        {
            if(nums1[l]>nums2[r]) nums1[k--]=nums1[l--];
            else nums1[k--]=nums2[r--];
        }
        while(l>=0) nums1[k--]=nums1[l--];
        while(r>=0) nums1[k--]=nums2[r--];
    }
};

350.两个数组的交集2

350. 两个数组的交集 II

哈希表法

先在第一个数组里统计每个数字出现的次数

再遍历第二个数组 如果有该数字 则加入答案数组中 并减少hash中的次数

class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        unordered_map<int,int>mp;
        vector<int>a;
        for(int x:nums1) mp[x]++;
        for(int x:nums2)
            if(mp[x]>0) a.push_back(x),mp[x]--;   
        return a;
    }
};

排序+双指针

先排序,再用两个指针分别指向两个数组 

class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        int n1=nums1.size(),n2=nums2.size();
        sort(nums1.begin(),nums1.end());
        sort(nums2.begin(),nums2.end());
        int l=0,r=0;
        vector<int>a;
        while(l<n1&&r<n2)
        {
            if(nums1[l]<nums2[r]) l++;
            else if(nums1[l]>nums2[r]) r++;
            else a.push_back(nums1[l]),l++,r++;
        }
        return a;
    }
};

121.买卖股票的最佳时机

121. 买卖股票的最佳时机

贪心

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int minx=0x3f3f3f3f;
        int maxx=0;
        for(int i=0;i<prices.size();i++)
        {
            minx=min(minx,prices[i]);
            maxx=max(maxx,prices[i]-minx);
        }
        return maxx;
    }
};

动态规划

前i天的最大收益 = max{ 前i-1天的最大收益,第i天的价格 - 前i-1天中的最小价格 } 

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n=prices.size();
        vector<int>dp(n);
        dp[0]=0;
        int minp=prices[0];
        for(int i=1;i<n;i++)
        {
            dp[i]=max(dp[i-1],prices[i]-minp);
            minp=min(minp,prices[i]);
        }
        return dp[n-1];
    }
};

566.重塑矩阵

566. 重塑矩阵

class Solution {
public:
    vector<vector<int>> matrixReshape(vector<vector<int>>& mat, int r, int c) {
        int m=mat.size(),n=mat[0].size();
        if(n*m!=r*c) return mat;
        
        vector<vector<int>> res(r,vector<int>(c));
        for(int i=0;i<m*n;i++)
            res[i/c][i%c]=mat[i/n][i%n];
        return res;
    }
};

141.环形链表

141. 环形链表

哈希表 

class Solution {
public:
    bool hasCycle(ListNode *head) {
        set<ListNode*>mp;
        while(head!=NULL)
        {
            if(mp.count(head)) return true;
            mp.insert(head);
            head=head->next;
        }
        return false;
    }
};

快慢指针

用快慢指针判断环

class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode *f=head,*s=head;
        while(f!=NULL&&f->next!=NULL)//快指针一次移动两步呢
        {
            s=s->next;
            f=f->next->next;
            if(s==f) return true;
        }
        return false;
    }
};

21.合并两个有序链表

21. 合并两个有序链表

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode *pre=new ListNode(-1); //创建一个头节点
        ListNode *p=pre;
        while(l1!=NULL&&l2!=NULL)
        {
            if(l1->val>l2->val) p->next=l2,l2=l2->next;
            else p->next=l1,l1=l1->next; 
            p=p->next;
        }
        p->next= l1==NULL?l2:l1; //哪个链表没放完 把哪个链表加在末尾
        return pre->next;
    }
};

20.有效的括号

20. 有效的括号

class Solution {
public:
    bool isValid(string s) {
        stack<char>st;
        for(auto c:s)
        {
            if(c=='('||c=='{'||c=='[') st.push(c);
            if(st.empty()) return false;
            if(c==')')
                if(st.top()!='(') return false;
                else st.pop();
            if(c==']') 
                if(st.top()!='[') return false;
                else st.pop();
            if(c=='}')
                if(st.top()!='{') return false;
                else st.pop();
        }
        return st.empty()? true:false;
    }
};

118.杨辉三角

118. 杨辉三角

class Solution {
public:
    vector<vector<int>> generate(int n) {
        vector<vector<int>> a(n);
        for(int i=0;i<n;i++)
        {
            a[i].resize(i+1);
            for(int j=0;j<=i;j++)
            {
                a[i][j]=1;
                if(j>0&&j<i) a[i][j]=a[i-1][j-1]+a[i-1][j];
            }            
        }

        return a;
    }
};

36.有效的数独

36. 有效的数独

行标决定一组box的起始位置(因为box为3行,所以除3取整得到组号,又因为每组box为3个,所以需要乘3),列标再细分出是哪个box(因为box是3列,所以除3取整)

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>&g) {
        int r[9][10]={0}; //存每一行是否出现过
        int c[9][10]={0}; //存每一列是否出现过
        int box[9][10]={0}; //一共9个box 判断每个盒子数是否出现过
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++)
            {
                if(g[i][j]=='.') continue;
                int cur=g[i][j]-'0';
                if(r[i][cur]) return false;
                if(c[j][cur]) return false;
                if(box[j/3+i/3*3][cur]) return false;

                r[i][cur]=1;
                c[j][cur]=1;
                box[j/3+i/3*3][cur]=1;
            }
        return true;
    }
};

73.矩阵置零

73. 矩阵置零

typedef pair<int,int> PII;
class Solution {
public:
    void setZeroes(vector<vector<int>>& g) {
        int m=g.size(),n=g[0].size();
        vector<PII>v;
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++)
                if(g[i][j]==0) v.push_back({i,j});
        for(auto x:v)
        {
            for(int i=0;i<m;i++) g[i][x.second]=0;
            for(int i=0;i<n;i++) g[x.first][i]=0;
        }
    }
};

387.字符串的第一个唯一字符

387. 字符串中的第一个唯一字符

class Solution {
    public int firstUniqChar(String s) {
        Map<Character,Integer> mp=new HashMap<>();
        for(int i=0;i<s.length();i++)
        {
            char c=s.charAt(i);
            mp.put(c,mp.getOrDefault(c,0)+1);//相当于mp[s[i]]++
        }
        for(int i=0;i<s.length();i++)
            if(mp.get(s.charAt(i))==1) return i;//相当于mp[s[i]]==1
        return -1;
    }
}

383.赎金信

 383. 赎金信

class Solution {
    public boolean canConstruct(String r, String m) {
        Map<Character,Integer> mp=new HashMap<>();
        for(char c:m.toCharArray()) mp.put(c,mp.getOrDefault(c,0)+1);
        for(char ch:r.toCharArray())
        {
            mp.put(ch,mp.getOrDefault(ch,0)-1);
            if(mp.get(ch)<0) return false;
        }
        return true;
    }
}
class Solution {
    public boolean canConstruct(String r, String m) {
        int[] cnt=new int[26];
        for(char c:m.toCharArray()) cnt[c-'a']++;
        for(char ch:r.toCharArray())
        {
            cnt[ch-'a']--;
            if(cnt[ch-'a']<0) return false;
        }
        return true;
    }
}

242.有效的字母异位词

242. 有效的字母异位词

class Solution {
    public boolean isAnagram(String s, String t) {
        int[] cnt=new int[26];
        for(char c:s.toCharArray()) cnt[c-'a']++;
        for(char ch:t.toCharArray()) cnt[ch-'a']--;
        for(int i=0;i<26;i++) if(cnt[i]!=0) return false;
        return true;
        }
    }

203.移除链表元素

203. 移除链表元素

思路一:删除头结点时另加考虑

  • 因为删掉头结点后,生成的新头结点也可能要删除,所以用循环
  • 此时的头结点不用删除,后续用常规的删除链表方法即可
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        //头结点值删除后 新的头结点的值可能也要删除 用循环
        while(head!=null&&head.val==val) head=head.next;
        if(head==null) return head;

        ListNode p=head;
        while(p.next!=null)
        {
            if(p.next.val==val) p.next=p.next.next;
            else p=p.next;
        }
        return head;
    }
}

思路二:添加一个虚拟头结点 

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode dummy=new ListNode(val+1);
        dummy.next=head;
        ListNode p=dummy;
        while(p.next!=null)
        {
            if(p.next.val==val) p.next=p.next.next;
            else p=p.next;
        }
        return dummy.next;
    }
}

思路三:递归

不会理解

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if(head==null) return null;
        head.next=removeElements(head.next,val);
        return head.val==val? head.next:head;
    }
}

206.反转链表

206. 反转链表

思路一:迭代

力扣

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode p=null;
        ListNode cur=head;
        while(cur!=null)
        {
            ListNode t=cur.next;
            cur.next=p;
            p=cur;
            cur=t;
        }
        return p;
    }
}

思路二:递归 

力扣

class Solution {
    public ListNode reverseList(ListNode head) {
        if(head==null||head.next==null) return head;

        ListNode cur=reverseList(head.next);//cur永远是最后一个点不动
        head.next.next=head;
        head.next=null;
        return cur;
    }
}

83.删除排序链表中的重复元素

83. 删除排序链表中的重复元素

思路:

头结点必然不可能重复

则用set存买每一个结点的值

如果p的下一个节点出现过 则直接跳过这个节点 否则后移p指针即可

class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if(head==null) return null;
        Set st=new HashSet<>();
        ListNode p=head;
        while(p.next!=null)
        {
            st.add(p.val);//头结点必然不可能重复呀 
            if(st.contains(p.next.val))
            {
                p.next=p.next.next;
            }else p=p.next;
        }
        return head;
    }
}

232.用栈实现队列

232. 用栈实现队列

java法

  • java中的栈pop和peek的异同:
  • 相同点:都返回栈顶元素的值
  • 不同点:pop会删除栈顶的值,peek不会删除
class MyQueue {

    Deque<Integer> inStack=new LinkedList<>();
    Deque<Integer> outStack=new LinkedList<>();
    
    public void push(int x) {
        inStack.push(x);
    }
    
    public int pop() {
        solve();
        return outStack.pop();
    }
    
    public int peek() {
        solve();
        return outStack.peek();
    }
    
    public boolean empty() {
        return inStack.isEmpty()&&outStack.isEmpty();
    }

    private void solve()
    {
        if(outStack.isEmpty())//输出栈必须为空 才能从输入栈里拿元素往里边放
        {
            while(!inStack.isEmpty())
            {
                outStack.push(inStack.pop());
            }
        }
    }
}

c++法:

  •  和Java不同,c++的pop纯删除栈顶元素,不返回栈顶的值
  • 这里可以嵌套使用已定义的 pop(),减少代码量
class MyQueue {
public:

    stack<int> inst; //输入栈
    stack<int> outst; //输出栈
    
    void push(int x) {
        inst.push(x);
    }
    
    int pop() {
        if(outst.empty()) //只有输出栈为空时 才能把输入栈里的元素往里放
        {
            while(!inst.empty())//把输入栈的元素都放进输出栈
            {
                outst.push(inst.top());
                inst.pop();
            }
        }
        int k=outst.top();
        outst.pop();
        return k;
    }
    
    int peek() { // peek 返回队头元素
        int res=this->pop();
        outst.push(res);//因为pop删掉了栈顶元素 所以要把栈顶元素再加回去
        return res;
    }
    
    bool empty() {
        return inst.empty()&&outst.empty();
    }
};

144.二叉树前序遍历

144. 二叉树的前序遍历

1、递归法

DLR

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        ArrayList<Integer> v=new ArrayList<>();
        pre(root,v);
        return v;
    }

    public void pre(TreeNode root,ArrayList v)
    {
        if(root==null) return;
        v.add(root.val);
        pre(root.left,v);
        pre(root.right,v);
    }
}

2、迭代法 

来存

先把根节点入栈,输出根节点,因为先输出左子树再输出右子树,所以右子树先入栈,左子树后入栈,然后依次出栈,顺序刚好是DLR

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        ArrayList<Integer> v=new ArrayList<>();
        if(root==null) return v;
        Deque<TreeNode> st=new LinkedList<>();
        st.push(root);
        
        while(!st.isEmpty())
        {
            TreeNode n=st.pop();
            v.add(n.val);
            if(n.right!=null) st.push(n.right);
            if(n.left!=null) st.push(n.left);
        }
        return v;
    }
}

94、二叉树的中序遍历

94. 二叉树的中序遍历

1、递归法

LDR

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        ArrayList<Integer> v=new ArrayList<>();
        in(root,v);
        return v;
    }

    public void in(TreeNode root,ArrayList v)
    {
        if(root==null) return;
        in(root.left,v);
        v.add(root.val);
        in(root.right,v);
    }
}

2、迭代法

力扣

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        ArrayList<Integer> v=new ArrayList<>();
        if(root==null) return v;
        Deque<TreeNode> st=new LinkedList<>();
        
        while(!st.isEmpty()||root!=null)
        {
            while(root!=null)
            {
                st.push(root);
                root=root.left;
            }
            root=st.pop();
            v.add(root.val);
            root=root.right;
        }
        return v;
    }
}

145.二叉树的后序遍历

145. 二叉树的后序遍历

1、递归法

LRD

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        ArrayList<Integer> v=new ArrayList<>();
        post(root,v);
        return v;
    }

    public void post(TreeNode root,ArrayList v)
    {
        if(root==null) return ;
        post(root.left,v);
        post(root.right,v);
        v.add(root.val);
    }
}

2、迭代法 

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        ArrayList<Integer> v=new ArrayList<>();
        Deque<TreeNode> st=new LinkedList<>();
        if(root==null) return v;

        TreeNode pre=null;
        while(!st.isEmpty()||root!=null)
        {
            while(root!=null)
            {
                st.push(root);
                root=root.left;
            }
            root=st.pop();
            if(root.right==null||root.right==pre)//如果右子树被访问过或右子树为空 则可以将根节点输出
            {
                v.add(root.val);
                pre=root;//标记更新
                root=null;
            }else//如果右子树没有被访问 那么将当前节点压栈 访问右子树
            {
                st.push(root);
                root=root.right;
            }
        }
        return v;
    }
}

102.二叉树的层序遍历

102. 二叉树的层序遍历

队列

根节点入队,然后将该根节点的左右孩子入队

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> v=new ArrayList<>();
        if(root==null) return v;
        Queue<TreeNode> q=new LinkedList<>();
        q.offer(root);
        while(!q.isEmpty())
        {
            ArrayList<Integer> list=new ArrayList<>();
            int n=q.size();
            for(int i=0;i<n;i++)
            {
                TreeNode t=q.poll();
                list.add(t.val);
                if(t.left!=null) q.add(t.left);
                if(t.right!=null) q.add(t.right);
            }
            v.add(list);
        }
        return v;
    }
}

104.二叉树的最大深度

104. 二叉树的最大深度

1、dfs

class Solution {
    public int maxDepth(TreeNode root) {
        return root==null? 0:Math.max(maxDepth(root.left),maxDepth(root.right))+1;
    }
}

2、bfs 

本质上就是层序遍历啦 看看有几层

class Solution {
    public int maxDepth(TreeNode root) {
        Queue<TreeNode> q=new LinkedList<>();
        if(root==null) return 0;
        q.offer(root);
        int res=0;
        while(!q.isEmpty())
        {
            int n=q.size();
            while(n>0)
            {
                TreeNode t=q.poll();
                if(t.left!=null) q.offer(t.left);
                if(t.right!=null) q.offer(t.right);
                n--;
            }
            res++;
        }
        return res;
    }
}

101.对称二叉树

 101. 对称二叉树

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root==null) return true;
        return check(root.left,root.right);
    }

    boolean check(TreeNode n1,TreeNode n2)
    {
        if(n1==null&&n2==null) return true;
        if(n1==null||n2==null||n1.val!=n2.val) return false;
        return check(n1.left,n2.right)&&check(n1.right,n2.left);
    }
}

226.翻转二叉树

226. 翻转二叉树

1、递归法

先把当前结点的左右孩子互换 再依次递归处理该结点的左右孩子

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root==null) return null;
        //将当前结点的左右孩子互换
        TreeNode t=root.left;
        root.left=root.right;
        root.right=t;
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }
}

2、迭代法 

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root==null) return null;
        Deque<TreeNode> q=new LinkedList<>();
        q.offer(root);
        while(!q.isEmpty())
        {
            TreeNode t=q.poll();
            TreeNode tmp=t.left;
            t.left=t.right;
            t.right=tmp;
            if(t.left!=null) q.offer(t.left);
            if(t.right!=null) q.offer(t.right);
        }
        return root;
    }
}

112.路径总和

112. 路径总和

1、用cur记录当前路径长度

如果到叶子结点 则判断是否cur==sum

class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        return dfs(root,0,targetSum);
    }

    private boolean dfs(TreeNode root,int cur,int sum)
    {
        if(root==null) return false;
        cur+=root.val;
        if(root.left==null&&root.right==null) return cur==sum;
        else return dfs(root.left,cur,sum)||dfs(root.right,cur,sum);//左右子树只要有一条路径可以就ok
    }
}

2、直接用sum减去所经过的结点

如果到叶子结点 则判断sum减掉叶子结点的值后是否为0

class Solution {
    public boolean hasPathSum(TreeNode root, int sum) {
        if(root==null) return false;

        if(root.left==null&&root.right==null) return sum-root.val==0;
        else return hasPathSum(root.left,sum-root.val)||hasPathSum(root.right,sum-root.val);
    }
}

700.二叉搜索树中的搜索

700. 二叉搜索树中的搜索

class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        if(root==null) return null;
        if(root.val==val) return root;
        return val>root.val? searchBST(root.right,val):searchBST(root.left,val);
    }
}

701.二叉搜索树的插入操作

701. 二叉搜索树中的插入操作

class Solution {
    public TreeNode insertIntoBST(TreeNode root, int val) {
        if(root==null) return new TreeNode(val);

        if(val>root.val) root.right=insertIntoBST(root.right,val);
        else root.left=insertIntoBST(root.left,val);

        return root;
    }
}

98.验证二叉搜索树

98. 验证二叉搜索树

1、递归

  • 二叉搜索树的左子树的值均小于父节点,所以root.val作为左子树的上界
  • 二叉搜索树的右子树的值均大于父节点,所以root.val作为右子树的下界
class Solution {
    public boolean isValidBST(TreeNode root) {
        return dfs(root,Long.MIN_VALUE,Long.MAX_VALUE);
    }
    public boolean dfs(TreeNode root,long minx,long maxx)
    {
        //空树也是搜索树
        if(root==null) return true;

        if(root.val<=minx||root.val>=maxx) return false;
        //左子树以父节点的值为上界 右子树以父节点的值为下界
        return dfs(root.left,minx,root.val)&&dfs(root.right,root.val,maxx);
    }
}

2、中序遍历判断二叉搜索树

中序遍历后如果是递增顺序,则该二叉树为二叉搜索树 

class Solution {
    public boolean isValidBST(TreeNode root) {
        List<Integer> res=new ArrayList<>();
        in(root,res);
        for(int i=1;i<res.size();i++)
            if(res.get(i)<=res.get(i-1)) return false;
        return true;
    }
    public void in(TreeNode root,List res)
    {
        if(root==null) return;
        in(root.left,res);
        res.add(root.val);
        in(root.right,res);
    }
}
class Solution {
    public boolean isValidBST(TreeNode root) {
        List<Integer> res=new ArrayList<>();
        in(root,res);
        for(int i=1;i<res.size();i++)
            if(res.get(i)<=res.get(i-1)) return false;
        return true;
    }
    public void in(TreeNode root,List res)
    {
        if(root==null) return;
        Deque<TreeNode> st=new LinkedList<>();
        while(!st.isEmpty()||root!=null)
        {
            while(root!=null)
            {
                st.push(root);
                root=root.left;
            }
            root=st.pop();
            res.add(root.val);
            root=root.right;
        }
    }
}

653.两数之和4 - 输入二叉搜索树

653. 两数之和 IV - 输入二叉搜索树

遍历二叉树 哈希表存下每个结点的值 如果哈希表内存在k-root.val则说明有

然后递归遍历左右子树

class Solution {
    Set<Integer> s=new HashSet<>();
    public boolean findTarget(TreeNode root, int k) {
        if(root==null) return false;
        if(s.contains(k-root.val)) return true;
        s.add(root.val);
        return findTarget(root.left,k)||findTarget(root.right,k);
    }
}

235.二叉搜索树的最近公共祖先

235. 二叉搜索树的最近公共祖先

  1. 如果 p,q 值 都 < root 的值,就去左子树
  2. 如果 p,q 值 都 > root 的值,就去右子树
  3. 如果p q一个分布在左子树 一个分布在右子树 则公共祖先就是当前的root
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        
        if(root.val>p.val&&root.val>q.val) 
            return lowestCommonAncestor(root.left,p,q);
        else if(root.val<p.val&&root.val<q.val) 
            return lowestCommonAncestor(root.right,p,q);
        
        return root;
    }
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
作为一个程序员,算法数据结构是你必须掌握的基本知识之一。它们是解决问题和优化代码性能的关键工具。 算法是一系列定义良好的步骤,用于解决特定问题或执行特定任务。它们可以是数学公式、逻辑推理或一系列编程指令。算法有助于解决各种问题,例如查找、排序、图形处理等。 数据结构是组织和存储数据的方式。它们可以是简单的变量、数组、链表、栈、队列、树或图等。选择合适的数据结构可以显著提高算法的效率和性能。 入门算法数据结构,你可以从以下几个方面开始学习: 1. 掌握基本的数据结构:了解数组、链表、栈和队列等基本数据结构的概念、特点及其操作。 2. 学习常见的算法:了解常见的排序算法(如冒泡排序、插入排序、快速排序)、查找算法(如线性查找、二分查找)以及递归算法等。 3. 理解复杂度分析:学习如何分析算法的时间复杂度和空间复杂度,了解如何评估算法的效率和性能。 4. 解决实际问题:通过练习和实践,尝试用算法数据结构解决一些实际的编程问题,例如字符串处理、图形处理等。 除了自学,你可以参考一些经典的教材和在线教程来加深理解。一些推荐的资源包括《算法导论》、《数据结构算法分析》、LeetCode等在线平台。 记住,算法数据结构是一个长期学习的过程,不仅需要理解概念,还需要实践和不断地思考如何应用它们解决实际问题。祝你在算法数据结构学习中取得好成果!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值