每日leetcode - CodeTop

leetcode - 215. 数组中的第K个最大元素

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

方法1:使用Priority构建小顶堆,O(nlogk)

class Solution {
    public int findKthLargest(int[] nums, int k) {
        if(nums.length==0 || k<=0) return 0;
        //构建一个小顶堆
        PriorityQueue<Integer> queue = new PriorityQueue<>();
        for(int i=0;i<nums.length;i++){
            if(queue.size()<k){
                queue.add(nums[i]);
            }else if(queue.peek()<nums[i]){
                queue.poll();
                queue.add(nums[i]);
            }
        }

        return queue.peek();
    }
}

方法2:快速排序,O(nlogn)

class Solution {
    public int findKthLargest(int[] nums, int k) {
        if(nums.length==0 || k<=0) return 0;
        int left = 0;
        int right = nums.length-1;
        quickSort(left,right,nums);
        return nums[nums.length-k];
    }

    private void quickSort(int left, int right, int[] nums) {
        if(left>right) return;
        int index = getIndex(left,right,nums);
        quickSort(left,index-1,nums);
        quickSort(index+1,right,nums);
    }

    private int getIndex(int left, int right, int[] nums) {
        int tmp = nums[left];
        while (left<right){
            while (left<right && nums[right]>=tmp){
                right--;
            }
            nums[left] = nums[right];
            while (left<right && nums[left]<=tmp){
                left++;
            }
            nums[right] = nums[left];
        }
        nums[left] = tmp;
        return left;
    }
}

leetcode - 206. 反转链表

反转一个单链表。

class Solution {
    public ListNode reverseList(ListNode head) {
        if(head==null) return null;
        ListNode cur = head;
        ListNode pre = null;
        while (cur!=null){
            ListNode temp = cur.next;
            cur.next  = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }
}

leetcode - 3. 无重复字符的最长子串

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

方法:哈希表

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s==null) return 0;
        HashMap<Character,Integer> map = new HashMap<>();
        int res = 0;
        for(int start = 0,end = 0;end<s.length();end++){
            //遇到重复字符时,更新start
            if(map.containsKey(s.charAt(end))){
                start = Math.max(start,map.get(s.charAt(end))+1);
            }
            map.put(s.charAt(end),end);
            res = Math.max(res,end-start+1);
        }
        return res;
    }
}

leetcode - 15. 三数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> threeSum(int[] nums) {
        if(nums.length==0) return res;
        Arrays.sort(nums);
        for(int i=0;i<nums.length;i++){
            if(i>0 && nums[i]==nums[i-1]) continue;
            int left = i+1;
            int right = nums.length-1;
            while (left<right){
                int sum = nums[left]+nums[right]+nums[i];
                if(sum==0){
                    res.add(Arrays.asList(nums[left],nums[right],nums[i]));
                    while (left<right && nums[left]==nums[left+1]) left++;
                    while (left<right && nums[right]==nums[right-1]) right--;
                    left++;
                    right--;
                }else if(sum<0){
                    left++;
                }else{
                    right--;
                }
            }
        }
        return res;
    }
}

leetcode - 94. 二叉树的中序遍历

给你二叉树的根节点 root ,返回它节点值的 中序 遍历。

方法1:递归

class Solution {
    List<Integer> res = new ArrayList<>();
    public List<Integer> inorderTraversal(TreeNode root) {
        if(root==null) return res;
        dfs(root);
        return res;
    }

    private void dfs(TreeNode root) {
        if(root==null) return;
        dfs(root.left);
        res.add(root.val);
        dfs(root.right);
    }
}

方法2:迭代

class Solution {
    List<Integer> res = new ArrayList<>();
    public List<Integer> inorderTraversal(TreeNode root) {
        if(root==null) return res;
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()){
            TreeNode node = stack.pop();
            if(node!=null){
                if(node.right!=null) stack.push(node.right);
                stack.push(node);
                stack.push(null);
                if(node.left!=null) stack.push(node.left);
            }else{
                res.add(stack.pop().val);
            }
        }
        return res;
    }
}

leetcode - 144. 二叉树的前序遍历

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

方法1:递归

class Solution {
    List<Integer> res = new ArrayList<>();
    public List<Integer> preorderTraversal(TreeNode root) {
        if(root==null) return res;
        dfs(root);
        return res;
    }

    private void dfs(TreeNode root) {
        if(root==null) return;
        res.add(root.val);
        dfs(root.left);
        dfs(root.right);
    }
}

方法2:迭代

class Solution {
    List<Integer> res = new ArrayList<>();
    public List<Integer> preorderTraversal(TreeNode root) {
        if(root==null) return res;
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()){
            TreeNode node = stack.pop();
            if(node!=null){
                if(node.right!=null) stack.push(node.right);
                if(node.left!=null) stack.push(node.left);
                stack.push(node);
                stack.push(null);
            }else{
                res.add(stack.pop().val);
            }
        }
        return res;
    }
}

leetcode - 141. 环形链表

给定一个链表,判断链表中是否有环。如果链表中存在环,则返回 true 。 否则,返回 false 。

方法:快慢指针,快指针走两步,慢指针走一步,两指针相遇的时候就是环形链表

public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head==null) return false;
        ListNode fast = head;
        ListNode slow = head;
        while (true){
            if(fast==null || fast.next==null) return false;
            fast = fast.next.next;
            slow = slow.next;
            if(fast==slow){
                return true;
            }
        }
    }
}

leetcode - 142. 环形链表 II

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

方法:快慢指针

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        while (true){
            if(fast==null || fast.next==null) return null;
            fast = fast.next.next;
            slow = slow.next;
            if(fast==slow) break;
        }
        slow = head;
        while (slow!=fast){
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }
}

leetcode - 199. 二叉树的右视图

给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

class Solution {
    List<Integer> res = new ArrayList<>();
    public List<Integer> rightSideView(TreeNode root) {
        if(root==null) return res;
        dfs(root,0);
        return res;
    }

    private void dfs(TreeNode root, int level) {
        if(root==null) return;
        //二叉树的层数=res的大小时,说明当前元素还没添加进去
        if(res.size()==level){
            res.add(root.val);
        }
        level++;
        dfs(root.right,level);
        dfs(root.left,level);
    }
}

leetcode - 160. 相交链表

编写一个程序,找到两个单链表相交的起始节点。

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode cur1 = headA;
        ListNode cur2 = headB;
        while (cur1!=cur2){
            if(cur1==null){
                cur1 = headB;
            }else{
                cur1 = cur1.next;
            }
            if(cur2==null){
                cur2 = headA;
            }else{
                cur2 = cur2.next;
            }
        }
        return cur1;
    }
}

leetcode - 92. 反转链表 II

反转从位置 mn 的链表。请使用一趟扫描完成反转。

方法:使用两个指针pre和start并移动到要反转的节点处,然后反转即可

class Solution {
    public ListNode reverseBetween(ListNode head, int m, int n) {
        if(head==null) return null;
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode pre = dummy;
        ListNode start = head;

        //将pre2移动至要反转的节点位置处
        for(int i=0;i<m-1;i++){
            pre = pre.next;
            start = start.next;
        }

        //反转链表,反转的次数就是n-m
        for(int i=0;i<n-m;i++){
            ListNode end = start.next;
            ListNode nextStart = start.next.next;
            start.next = nextStart;
            end.next = pre.next;
            pre.next = end;
        }
        return dummy.next;
    }
}

leetcode - 104. 二叉树的最大深度

给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

方法:递归

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

leetcode - 110. 平衡二叉树

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

方法:计算当前节点的左右子树的高度,判断高度差;判断左右子树是否是平衡二叉树

class Solution {
    public boolean isBalanced(TreeNode root) {
        if(root==null) return true;
        return Math.abs(dfs(root.left)-dfs(root.right))<=1 && isBalanced(root.left) && isBalanced(root.right);
    }

    private int dfs(TreeNode root) {
        if(root==null) return 0;
        int leftDepth = dfs(root.left);
        int rightDepth = dfs(root.right);
        return Math.max(leftDepth,rightDepth)+1;
    }
}

leetcode - 543. 二叉树的直径

给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。

class Solution {
    int maxDepth = 0;
    public int diameterOfBinaryTree(TreeNode root) {
        if(root==null) return 0;
        dfs(root);
        return maxDepth;
    }

    private int dfs(TreeNode root) {
        if(root==null) return 0;
        int leftDepth = dfs(root.left);
        int rightDepth = dfs(root.right);
        // 讲过该节点的二叉树的直径的最大值    
        maxDepth = Math.max(leftDepth+rightDepth,maxDepth);
        // 返回该树的高度
        return Math.max(leftDepth,rightDepth)+1;
    }
}

leetcode - 53. 最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

class Solution {
    public int maxSubArray(int[] nums) {
        if(nums.length==0) return 0;
        int[] dp = new int[nums.length+1];
        dp[0] = nums[0];
        int res = dp[0];
        for(int i=1;i<nums.length;i++){
            if(dp[i-1]<0){
                dp[i] = nums[i];
            }else{
                dp[i] = nums[i]+dp[i-1];
            }
            res = Math.max(dp[i],res);
        }
        return res;
    }
}

leetcode - 69. x 的平方根

实现 int sqrt(int x) 函数。计算并返回 x 的平方根,其中 x 是非负整数。由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。

方法:二分查找

class Solution {
    public int mySqrt(int x) {
        //注意,x为非负整数,同时X可能会很大
        if(x==0) return 0;
        long start = 1;
        long end = x;
        while (start+1<end) {
            long mid = start + (end - start) / 2;
            if (mid * mid > x) {
                end = mid;
            } else {
                start = mid;
            }
        }
        return (int)start;
    }
}

leetcode - 20. 有效的括号

给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

方法:栈,遇到一个就压入一个

class Solution {
    public boolean isValid(String s) {
        if(s==null || s.length()==0) return false;
        Stack<Character> stack = new Stack<>();
        for(int i=0;i<s.length();i++){
            if(s.charAt(i)=='('){
                stack.push(')');
            }else if(s.charAt(i)=='['){
                stack.push(']');
            }else if(s.charAt(i)=='{'){
                stack.push('}');
            //如果以上条件都不符合说明为],),}或者是字符和栈顶的不相同    
            }else{
                if(stack.isEmpty()){
                    return false;
                }
                if(stack.pop()!=s.charAt(i)){
                    return false;
                }
            }
        }
        return stack.isEmpty();
    }
}

leetcode - 415. 字符串相加

给定两个字符串形式的非负整数 num1num2 ,计算它们的和。

方法:双指针

class Solution {
    public String addStrings(String num1, String num2) {
        //定义两个指针,跟别指向num1和num2末尾
        int i = num1.length()-1;
        int j = num2.length()-1;
        //进位
        int carry = 0;
        StringBuilder sb = new StringBuilder();
        while (i>=0 || j>=0){
            int sum = 0;
            if(i>=0){
                sum = sum + num1.charAt(i)-'0';
                i--;
            }
            if(j>=0){
                sum = sum + num2.charAt(j)-'0';
                j--;
            }
            sum = sum+carry;
            sb.append(sum%10);
            carry = sum/10;
        }
        if(carry==1){
            sb.append("1");
        }
        return sb.reverse().toString();
    }
}

leetcode - 33. 搜索旋转排序数组

给你一个整数数组 nums ,和一个整数 target 。该整数数组原本是按升序排列,但输入时在预先未知的某个点上进行了旋转。(例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。

方法:二分查找

class Solution {
    public int search(int[] nums, int target) {
        if(nums.length==0 || nums==null) return 0;
        int start = 0;
        int end = nums.length-1;
        while (start+1<end){
            int mid = start+(end-start)/2;
            //如果前半段有序
            if(nums[start]<nums[mid]){
                if(nums[start]<=target && target<=nums[mid]){
                    end = mid;
                }else{
                    start = mid;
                }
            }else{
                if(nums[mid]<=target && target<=nums[end]){
                    start = mid;
                }else{
                    end = mid;
                }
            }
        }
        if(nums[start]==target) return start;
        else if(nums[end]==target) return end;
        return -1;
    }
}

leetcode - 876. 链表的中间结点

给定一个头结点为 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

方法:快慢指针,需要分两种情况,如果链表长度为奇数满足fast!=null ,如果链表长度为偶数满足fast.next!=null

class Solution {
    public ListNode middleNode(ListNode head) {
        if(head==null) return null;
        ListNode fast = head;
        ListNode slow = head;
        while (fast!=null && fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }
}

leetcode - 234. 回文链表

请判断一个链表是否为回文链表。

class Solution {
    public boolean isPalindrome(ListNode head) {
        if(head==null) return true;
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode slow = dummy;
        ListNode fast = dummy;

        //找到链表的中间节点
        while (fast!=null && fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }

        //从中间节点处断开链表,并将后半部分反转
        ListNode cur = slow.next;
        slow.next = null;

        ListNode pre = null;
        while (cur!=null){
            ListNode tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }

        //让前后段链表的值进行比较
        slow = head;
        while (slow!=null && pre!=null){
            if(pre.val==slow.val){
                pre = pre.next;
                slow = slow.next;
            }else{
                return false;
            }
        }
        return true;
    }
}

leetcode - 101. 对称二叉树

给定一个二叉树,检查它是否是镜像对称的。

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

    private boolean dfs(TreeNode A, TreeNode B) {
        if(A==null && B!=null) return false;
        if(A!=null && B==null) return false;
        if(A==null && B==null) return true;
        return A.val==B.val && dfs(A.left,B.right) && dfs(A.right, B.left);
    }
}

leetcode - 62. 不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。问总共有多少条不同的路径?

方法:动态规划

class Solution {
    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 j=0;j<n;j++){
            dp[0][j] = 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];
    }
}

leetcode - 63. 不同路径 II

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int[][] dp = new int[obstacleGrid.length][obstacleGrid[0].length];
        for(int i=0;i<obstacleGrid.length;i++){
            if(obstacleGrid[i][0]==1) break;
            dp[i][0] = 1;
        }
        for(int j=0;j<obstacleGrid[0].length;j++){
            if(obstacleGrid[0][j]==1) break;
            dp[0][j] = 1;
        }
        for(int i=1;i<obstacleGrid.length;i++){
            for(int j=1;j<obstacleGrid[0].length;j++){
                if(obstacleGrid[i][j]==1) dp[i][j] = 0;
                else{
                    dp[i][j] = dp[i-1][j]+dp[i][j-1];
                }
            }
        }
        return dp[obstacleGrid.length-1][obstacleGrid[0].length-1];
    }
}

leetcode - 5. 最长回文子串

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

方法:动态规划

class Solution {
    public String longestPalindrome(String s) {
        if(s.length()==0) return null;
        //dp[i][j]代表[i,j]之间的字符串是否是回文子串
        boolean[][] dp = new boolean[s.length()][s.length()];
        dp[0][0] = true;
        int maxlen = 0;
        int begin = 0;
        for(int j=0;j<s.length();j++){
            for(int i=0;i<=j;i++){
                //判断dp[i][j]是否是回文子串:dp[i+1][j-1]是回文子串并且当前两个字符相等
                dp[i][j] = s.charAt(i)==s.charAt(j) && (j-i<=2||dp[i+1][j-1]);
                if(dp[i][j] && j-i+1>=maxlen){
                    maxlen = j-i+1;
                    begin = i;
                }
            }
        }
        return s.substring(begin,begin+maxlen);
    }
}

leetcode - 647. 回文子串

给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。

方法:动态规划

class Solution {
    public int countSubstrings(String s) {
        if(s.length()==0) return 0;
        int count = 0;
        boolean[][] dp = new boolean[s.length()][s.length()];
        dp[0][0] = true;
        for(int j=0;j<s.length();j++){
            for(int i=0;i<=j;i++){
                dp[i][j] = s.charAt(i)==s.charAt(j) && (j-i<=2||dp[i+1][j-1]);
                if(dp[i][j]){
                    count++;
                }
            }
        }
        return count;
    }
}

leetcode - 78. 子集

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

**说明:**解集不能包含重复的子集。

方法:递归回溯

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> subsets(int[] nums) {
        if(nums.length==0) return res;
        dfs(nums,new ArrayList<Integer>(),0);
        return res;
    }

    private void dfs(int[] nums, ArrayList<Integer> path, int start) {
        res.add(new ArrayList<>(path));
        for(int i=start;i<nums.length;i++){
            path.add(nums[i]);
            //这里需要注意,不能有重复的,[1,2,3]和[1,3,2]是相同的
            dfs(nums,path,i+1);
            path.remove(path.size()-1);
        }
    }
}

leetcode - 46. 全排列

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

方法:递归回溯

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> permute(int[] nums) {
        if(nums.length==0) return res;
        boolean[] used = new boolean[nums.length];
        dfs(nums,new ArrayList<Integer>(),used);
        return res;
    }

    private void dfs(int[] nums, ArrayList<Integer> path, boolean[] used) {
        if(path.size()==nums.length){
            res.add(new ArrayList<Integer>(path));
        }
        for(int i=0;i<nums.length;i++){
            if(used[i]) continue;
            path.add(nums[i]);
            used[i] = true;
            dfs(nums,path,used);
            path.remove(path.size()-1);
            used[i] =false;
        }
    }
}

leetcode - 47. 全排列 II

给定一个可包含重复数字的序列 nums按任意顺序 返回所有不重复的全排列。

方法:递归回溯

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> permuteUnique(int[] nums) {
        if(nums.length==0) return res;
        Arrays.sort(nums);
        boolean[] used = new boolean[nums.length];
        dfs(nums,new ArrayList<Integer>(),used);
        return res;
    }

    private void dfs(int[] nums, ArrayList<Integer> path, boolean[] used) {
        if(path.size()==nums.length){
            res.add(new ArrayList<Integer>(path));
            return;
        }
        for(int i=0;i<nums.length;i++){
            if(used[i]) continue;
            if(i>0 && nums[i]==nums[i-1] && used[i-1]==false) continue;

            path.add(nums[i]);
            used[i] = true;

            dfs(nums,path,used);

            path.remove(path.size()-1);
            used[i] =false;
        }
    }
}

leetcode - 39. 组合总和

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的数字可以无限制重复被选取。

方法:递归回溯

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        if(candidates.length==0) return res;
        dfs(candidates,new ArrayList<Integer>(),target,0);
        return res;
    }

    private void dfs(int[] candidates, ArrayList<Integer> path, int target,int start) {
        if(target==0){
            res.add(new ArrayList<>(path));
            return;
        }
        for(int i=start;i<candidates.length;i++){
            if(target<candidates[i]) continue;

            path.add(candidates[i]);
            target = target - candidates[i];
            //因为可以重复选择,因此是i而不是i+1
            dfs(candidates,path,target,i);
            path.remove(path.size()-1);
            target = target + candidates[i];
        }
    }
}

leetcode - 40. 组合总和 II

给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用一次。

说明:

所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。

方法:递归回溯

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        if(candidates.length==0) return res;
        Arrays.sort(candidates);
        boolean[] used = new boolean[candidates.length];
        dfs(candidates,new ArrayList<Integer>(),target,0,used);
        return res;
    }

    private void dfs(int[] candidates, ArrayList<Integer> path, int target,int start,boolean[] used) {
        if(target==0){
            res.add(new ArrayList<>(path));
            return;
        }
        for(int i=start;i<candidates.length;i++){
            if(used[i]) continue;
            if(i>0 && candidates[i]==candidates[i-1] && used[i-1]==false) continue;
            if(target<candidates[i]) continue;

            path.add(candidates[i]);
            target = target - candidates[i];
            used[i] = true;
            
            dfs(candidates,path,target,i,used);
            
            used[i] = false;
            path.remove(path.size()-1);
            target = target + candidates[i];
        }
    }
}

leetcode - 70. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

**注意:**给定 n 是一个正整数。

方法:动态规划

class Solution {
    public int climbStairs(int n) {
        if(n==0) return 0;
        if(n==1) return 1;
        if(n==2) return 2;
        int[] dp = new int[n+1];
        dp[0] = 0;
        dp[1] = 1;
        dp[2] = 2;
        for(int i=3;i<=n;i++){
            dp[i] = dp[i-1]+dp[i-2];
        }
        return dp[n];
    }
}

leetcode - 1143. 最长公共子序列

给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。

若这两个字符串没有公共子序列,则返回 0。

方法:动态规划

class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        int[][] dp = new int[text2.length()+1][text1.length()+1];
        dp[0][0] = 0;
        for(int i=1;i<=text2.length();i++){
            for(int j=1;j<=text1.length();j++){
                if(text1.charAt(j-1)==text2.charAt(i-1)){
                    dp[i][j] = dp[i-1][j-1]+1;
                }else{
                    dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
                }
            }
        }
        return dp[text2.length()][text1.length()];
    }
}

leetcode - 704. 二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

class Solution {
    public int search(int[] nums, int target) {
        if(nums.length==0) return 0;
        int start = 0;
        int end = nums.length-1;
        while (start+1<end){
            int mid = start +(end-start)/2;
            if(nums[mid]<target){
                start = mid;
            }else{
                end = mid;
            }
        }
        if(nums[start]==target) return start;
        if(nums[end]==target) return end;
        return -1;
    }
}

leetcode - 300. 最长上升子序列

class Solution {
    public int lengthOfLIS(int[] nums) {
        if(nums.length==0) return 0;
        int[] dp = new int[nums.length];
        int res = 0;
        for(int i=0;i<nums.length;i++){
            dp[i] = 1;
            for(int j=0;j<i;j++){
                //如果前面的数比当前nums[i]大,将长度加1,就将每次计算的dp[i]进行比较
                if(nums[i]>nums[j]){
                    dp[i] = Math.max(dp[j]+1,dp[i]);
                }
            }
            res = Math.max(res,dp[i]);
        }
        return res;
    }
}

排序算法 - 冒泡排序算法

时间复杂度:O(n^2)

class Solution {
    public static void main(String[] args) {
        int[] arr = {15,23,7,47};
        buboolSort(arr);
        for(int i=0;i<arr.length;i++){
            System.out.print(arr[i]+" ");
        }
    }
    public static int[] buboolSort(int[] nums) {
          //第一个for循环代表需要比较多少轮
          for(int i=0;i<nums.length-1;i++){
              /**
             * 在每轮排序中,比较相邻两个数的大小,如果前面的数比后面的数大就交换位置
             * 第一轮排序i=0,n个数需要比较n-1次
             * 第二轮排序i=1,第一大的数已经确定不需要再进行比较,n-1-1次
             * 第三轮排序i=2,第二大的数已经确定不需要再进行比较,n-1-1-1次
             */
              for(int j=0;j<nums.length-1-i;j++){
                  //如果前面的数比后面的数大,就交换位置
                  if(nums[j]>nums[j+1]){
                      int tmp = nums[j];
                      nums[j] = nums[j+1];
                      nums[j+1] = tmp;
                  }
              }
          }
          return nums;
    }
}

排序算法 - 快速排序算法

时间复杂度:O(nlogn)

class Solution {
    public static void main(String[] args) {
        int[] arr = {15,23,7,47};
        int start = 0;
        int end = arr.length-1;
        quickSort(arr,start,end);
        for(int i=0;i<arr.length;i++){
            System.out.print(arr[i]+" ");
        }
    }
    public static void quickSort(int[] nums,int start,int end) {
        if(start>end) return;
        int index = getIndex(nums,start,end);
        quickSort(nums,start,index-1);
        quickSort(nums,index+1,end);
    }

    private static int getIndex(int[] nums, int start, int end) {
        int tmp = nums[start];
        while (start<end){
            while (start<end && nums[end]>=tmp){
                end--;
            }
            nums[start] = nums[end];
            while (start<end && nums[start]<=tmp){
                start++;
            }
            nums[end] = nums[start];
        }
        nums[start] = tmp;
        return start;
    }
}

排序算法 - 插入排序算法

时间复杂度:o(n^2)

class Solution {
    public static void main(String[] args) {
        int[] arr = {15,23,7,47};
        int start = 0;
        int end = arr.length-1;
        quickSort(arr);
        for(int i=0;i<arr.length;i++){
            System.out.print(arr[i]+" ");
        }
    }
    public static void quickSort(int[] nums) {
         for(int i=1;i<nums.length;i++){
             int insertNum = nums[i];
             int insertIndex = i;
             while (insertIndex>0 && nums[insertIndex-1]>insertNum){
                 nums[insertIndex] = nums[insertIndex-1];
                 insertIndex--;
             }
             nums[insertIndex] = insertNum;
         }
    }
}

排序算法 - 选择排序算法

时间复杂度:O(n^2)

class Solution {
    public static void main(String[] args) {
        int[] arr = {15,23,7,47};
        int start = 0;
        int end = arr.length-1;
        selectSort(arr);
        for(int i=0;i<arr.length;i++){
            System.out.print(arr[i]+" ");
        }
    }
    public static void selectSort(int[] nums) {
        for(int i=0;i<nums.length-1;i++){
            int minValue = nums[i];
            int minIndex = i;
            for(int j=i+1;j<nums.length;j++){
                if(nums[j]<minValue){
                    minValue = nums[j];
                    minIndex = j;
                }
            }
            nums[minIndex] = nums[i];
            nums[i] = minValue;
        }
    }
}

设计模式 - 饿汉式单例模式

class Single{
    //饿汉式直接创建对象
    private static Single single = new Single();
    private Single(){};
    //通过公共的构造方法返回对象
    public static Single getInstance(){
         return single;
    }
}

设计模式 - 懒汉式单例模式

class Single{
    private static Single single;
    private Single(){};
    public static Single getSingle(){
        if(single==null){
            single = new Single();
        }
        return single;
    }
}

线程安全,双检锁:

class Single{
    private static volatile Single single;
    private Single(){};
    public static Single getSingle(){
        if(single==null){
            synchronized (Single.class){
                if(single==null){
                    single = new Single();
                }
            }
        }
        return single;
    }
}

多线程 - 两种方式创建线程

方式1:使用Thread类创建两个线程并启动

class Test{
    public void test(){
        Thread t1 = new Thread("t1"){
            @Override
            public void run(){
                System.out.println("线程t1");
            }
        };
        t1.start();

        Thread t2 = new Thread("t2"){
            @Override
            public void run(){
                System.out.println("线程t2");
            }
        };
        t2.start();
    }
}

方式2:使用Runnable接口创建线程类,先创建线程主体,再传入Thread构造方法

class Demo{
    public void test(){
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("线程主体1");
            }
        };
        //向Thread类的构造方法中传入Runnable变量
        Thread t1 = new Thread(r1,"t1");
        t1.start();
        
        Runnable r2 = new Runnable() {
            @Override
            public void run() {
                System.out.println("线程主体2");
            }
        };
        Thread t2 = new Thread(r2,"t2");
        t2.start();
    }
}

多线程 - 创建两个线程

class Test{
    //共享变量
    private static int count = 0;
    //在main线程中创建两个线程t1和t2
    public static void main(String[] args){
        Thread t1 = new Thread("t1"){
            @Override
            public void run(){
                for(int i=0;i<100;i++){
                    count++;
                }
            }
        };
        Thread t2 = new Thread("t2"){
            @Override
            public void run(){
                for(int i=0;i<100;i++){
                    count--;
                }
            }
        };
        t1.start();
        t2.start();
    }
}

解决线程安全问题:

class Test{
    //共享变量
    private static volatile int count = 0;
    private static Object object = new Object();
    //在main线程中创建两个线程t1和t2
    public static void main(String[] args){
        Thread t1 = new Thread("t1"){
            @Override
            public void run(){
                for(int i=0;i<100;i++){
                    synchronized (object){
                        count++;
                    }
                }
            }
        };
        Thread t2 = new Thread("t2"){
            @Override
            public void run(){
                for(int i=0;i<100;i++){
                    synchronized (object){
                        count--;
                    }
                }
            }
        };
        t1.start();
        t2.start();
    }
}

多线程- 生产者和消费者模型

//创建一个消息类
class Message{
    private int id;
    private Object value;

    public Message(int id,Object value){
        this.id = id;
        this.value = value;
    }

    public void setId(int id){
        this.id = id;
    }

    public int getId(){
        return  id;
    }

    public void setValue(Object value){
        this.value = value;
    }

    public Object getValue(){
        return value;
    }
}

//创建一个生产者消费者
class MessageQueue{
    //创建一个消息队列,用来存放消息
    LinkedList<Message> queue = new LinkedList<>();

    private int capacity;

    public MessageQueue(int capacity){
        this.capacity = capacity;
    }

    //生产者线程生产消息
    public void put(Message message){
        synchronized (queue){
            //如果队列是满的,生产者线程在队列上等待
            while (queue.size()==capacity){
                try {
                    queue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //队列不满了,将消息加入队列的尾部
            queue.addLast(message);
            //唤醒等待中的消费者消费者线程,队列不空了
            queue.notifyAll();
        }
    }

    //消费者消费消息
    public Message get(){
        synchronized (queue){
            while (queue.isEmpty()){
                try {
                    queue.wait();
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }

            //队列不空了,消费消息,从队列中取出头部的第一个消息消费
            Message message = queue.removeFirst();
            queue.notifyAll();
            return message;
        }
    }
}
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页