【九九归一|算法强化】HOT 算法①

1. 每日温度【高频】

739. 每日温度 2022.7.27

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        int[] res = new int[temperatures.length];
        Stack<Integer> sk = new Stack<>();                         //单调栈
        for (int i = temperatures.length - 1; i >= 0; i--) {
            while (!sk.isEmpty() && temperatures[sk.peek()] <= temperatures[i]) {
                sk.pop();
            }
            res[i] = sk.isEmpty() ? 0 : sk.peek() - i;
            sk.push(i);
        }
        return res;
    }
}

2. N数之和

15. 三数之和 2022.7.27

力扣算法 Java 刷题笔记【nSum 问题】hot100(一)团灭 nSum 3

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        return nSum(nums, 3, 0, 0);
    }

    List<List<Integer>> nSum(int[] nums, int n, int start, int target) {
        List<List<Integer>> res = new LinkedList<>();
        if (n < 2 || nums.length < n) {
            return res;
        }
        if (n == 2) {
            int l = start, r = nums.length - 1;
            while (l < r) {
                int left = nums[l], right = nums[r];
                int sum = left + right;
                if (sum > target) {
                    r--;
                } 
                if (sum < target) {
                    l++;
                } 
                if (sum == target) {
                    res.add(Arrays.asList(left, right));                // Arrays.asList()
                    while (l < r && nums[l] == left) {                  // 剪枝
                        l++;
                    }
                    while (l < r && nums[r] == right) {
                        r--;
                    }
                }
            }
        }

        if (n > 2) {
            for (int i = start; i < nums.length; i++) {
                List<List<Integer>> tuples = nSum(nums, n - 1, i + 1, target - nums[i]);
                for (List<Integer> tuple : tuples) {
                    List<Integer> t = new LinkedList<>(tuple);    // 注意实例化
                    t.add(nums[i]);
                    res.add(t);
                }

                while (i < nums.length - 1 && nums[i] == nums[i + 1]) {
                    i++;
                }
            }
        }
        return res;
    }
}

3. 复原 IP 地址

93. 复原 IP 地址 2022.8.5

class Solution {
    static final int SEG_COUNT = 4;
    List<String> ans = new ArrayList<String>();
    int[] segments = new int[SEG_COUNT];

    public List<String> restoreIpAddresses(String s) {
        dfs(s, 0, 0);
        return ans;
    }

    public void dfs(String s, int segId, int segStart) {
        // 如果找到了 4 段 IP 地址并且遍历完了字符串,那么就是一种答案
        if (segId == SEG_COUNT) {
            if (segStart == s.length()) {
                StringBuffer ipAddr = new StringBuffer();
                for (int i = 0; i < SEG_COUNT; i++) {
                    ipAddr.append(segments[i]);
                    if (i != SEG_COUNT - 1) {
                        ipAddr.append('.');
                    }
                }
                ans.add(ipAddr.toString());
            }
            return;
        }

        // 如果还没有找到 4 段 IP 地址就已经遍历完了字符串,那么提前回溯
        if (segStart == s.length()) {
            return;
        }

        // 由于不能有前导零,如果当前数字为 0,那么这一段 IP 地址只能为 0
        if (s.charAt(segStart) == '0') {
            segments[segId] = 0;
            dfs(s, segId + 1, segStart + 1);
        }

        // 一般情况,枚举每一种可能性并递归
        int addr = 0;
        for (int segEnd = segStart; segEnd < s.length(); segEnd++) {
            addr = addr * 10 + (s.charAt(segEnd) - '0');
            if (addr > 0 && addr <= 0xFF) {
                segments[segId] = addr;
                dfs(s, segId + 1, segEnd + 1);
            } else {
                break;
            }
        }
    }
}

4. 简化路径【华子】

71. 简化路径 2022.7.27

class Solution {
    public String simplifyPath(String path) {
        String[] parts = path.split("/");
        Stack<String> stk = new Stack<>();
        // 借助栈计算最终的文件夹路径
        for (String part : parts) {
            if (part.isEmpty() || part.equals(".")) {
                continue;
            }
            if (part.equals("..")) {
                if (!stk.isEmpty()) stk.pop();
                continue;
            }
            stk.push(part);
        }
        // 栈中存储的文件夹组成路径
        String res = "";
        while (!stk.isEmpty()) {
            res = "/" + stk.pop() + res;
        }
        return res.isEmpty() ? "/" : res;
    }
}

5. 接雨水

42. 接雨水 2022.8.5

class Solution {
    public int trap(int[] height) {
        int left = 0, right = height.length - 1;
        int left_max = 0, right_max = 0;
        int res = 0;
        while (left < right) {
            left_max = Math.max(left_max, height[left]);
            right_max = Math.max(right_max, height[right]);

            if (left_max < right_max) {
                res += left_max - height[left];
                left++;
            } else {
                res += right_max - height[right];
                right--;
            }
        }

        return res;
    }
}

6. 轮转数组

189. 轮转数组 2022.8.5

class Solution {
    public void rotate(int[] nums, int k) {
        int n = nums.length;
        k %= n;
        reverse(nums, 0, n - 1);
        reverse(nums, 0, k - 1);
        reverse(nums, k, n - 1);
    }

    private void reverse(int[] nums, int start, int end) {
        for (int i = start, j = end; i < j; i++, j--) {
            int temp = nums[j];
            nums[j] = nums[i];
            nums[i] = temp;
        }
    }
}

7. 重排链表

143. 重排链表 2022.8.6

class Solution {
    public void reorderList(ListNode head) {
        Deque<ListNode> dq = new LinkedList<>();
        ListNode cur = head;
        while (cur != null) {
            dq.addLast(cur);
            cur = cur.next;
        }
        while (!dq.isEmpty()) {
            if (cur == null) {
                cur = dq.pollFirst();
            } else {
                cur.next = dq.pollFirst();
                cur = cur.next;
            }
            cur.next = dq.pollLast();
            cur = cur.next;
        }
        if (cur != null) {
            cur.next = null;
        }
    }
}

8. 只出现一次的数字

136. 只出现一次的数字 2022.8.6

class Solution {
    public int singleNumber(int[] nums) {
        int res = 0;
        for (int n : nums) {
            res ^= n;
        }
        return res;
    }
}

9. 最长回文子串

5. 最长回文子串 2022.8.7

力扣算法 Java 刷题笔记【链表篇】hot100(四)如何判断回文链表(简单) 3

class Solution {
    public String longestPalindrome(String s) {
        String res = "";
        for (int i = 0; i < s.length(); i++) {
            String String1 = palindrom(s, i, i + 1);
            String String2 = palindrom(s, i, i);
            res = res.length() > String1.length() ? res : String1;
            res = res.length() >String2.length() ? res : String2;
        }
        return res;
    }

    String palindrom(String s, int start, int end) {
        while (start >= 0 && end  < s.length() && s.charAt(start) == s.charAt(end)) {
            start--;
            end++;
        }
        return s.substring(start + 1, end);
    }
}

10. 回文链表

234. 回文链表 2022.8.7

class Solution {
    public boolean isPalindrome(ListNode head) {
        ListNode fast = head, slow = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }

        if (fast != null) {
            slow = slow.next;
        }

        ListNode newNode = reverse(slow);
        while (newNode != null) {
            if (newNode.val != head.val) {
                return false;
            }
            newNode = newNode.next;
            head = head.next;
        }
        return true;
    }

    ListNode reverse(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }

        ListNode last = reverse(head.next);
        head.next.next = head;
        head.next = null;
        return last;
    }
}

11. 相交链表

160. 相交链表 2022.8.7

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

12. 数组中的第 K 个最大元素(中等)

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

方法一:二叉堆(优先队列)【推荐】

class Solution {
    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        for (int e : nums) {
            pq.offer(e);
            if (pq.size() > k) {
                pq.poll();
            }
        }
        return pq.peek();
    }
}

方法二:快排

class Solution {
    public int findKthLargest(int[] nums, int k) {
        shuffle(nums);
        int lo = 0, hi = nums.length - 1;
        k = nums.length - k;
        while (lo <= hi) {
            int p = partition(nums, lo, hi);
            if (p < k) {
               lo = p + 1;
            } else if (p > k) {
                hi = p - 1;
            } else {
                return nums[p];
            }  
        }
        return -1;
    }

    // void sort(int[] nums, int lo, int hi) {
    //     if (lo >= hi) {
    //         return;
    //     }

    //     int p = partition(nums, lo, hi);
    //     sort(nums, lo, p - 1);
    //     sort(nums, p + 1, hi);
    // }

    int partition(int[] nums, int lo, int hi) {
        int pivot = nums[lo];
        int i = lo + 1, j = hi;

        while (i <= j) {
            while (j > lo && nums[j] > pivot) {
                j--;
            }
            while (i < hi && nums[i] <= pivot) {
                i++;
            }
            if (i >= j) {
                break;
            }
            swap(nums, i, j);
        }
        swap(nums, lo, j);
        return j;
    }

    void shuffle(int[] nums) {
        Random rand = new Random();
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            swap(nums, i, i + rand.nextInt(n - i));
        }
    }

    void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

13. K 个一组翻转链表

25. K 个一组翻转链表 2022.8.7

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        // 新建两个结点
        ListNode a = head, b = head;
        for (int i = 0; i < k; i++) {
            if (b == null) {
                return a;
            }
            b = b.next;
        }
        ListNode newNode = reverse(a, b);
        a.next = reverseKGroup(b, k);
        return newNode;  
    }
    
    ListNode reverse(ListNode a, ListNode b) {
        ListNode pre = null, cur = a, nxt = a;
        // 循环条件记得改为 b
        while (cur != b) {
            nxt = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nxt;
        }
        return pre;
    }
}

14. 不同路径

62. 不同路径 2022.8.8

class Solution {
    int[][] memo = null;
    public int uniquePaths(int m, int n) {
        memo = new int[m][n];
        return dp(m - 1, n - 1);
    }

    int dp(int i, int j) {
        if (i == 0 || j == 0) {
            return 1;
        }

        if (memo[i][j] != 0) {
            return memo[i][j];
        }

        memo[i][j] = dp(i - 1, j) + dp(i, j - 1);

        return memo[i][j];
    }
}

15. 零钱兑换

322. 零钱兑换 2022.8.8

public class Solution {
    public int coinChange(int[] coins, int amount) {
        int[] dp = new int[amount + 1];
        // 这里我们还得给dp[i]赋予一个尽量大的初始值
        for(int i = 0; i <= amount; i++) {
                dp[i] = amount + 1;
        }
        dp[0] = 0;
        for (int i = 1; i <= amount; i++) {
            // 计算机 dp[i] 所需要的最少硬币数量
            for (int j = 0; j < coins.length; j++) {
                if (coins[j] <= i) {
                    dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
                }
            }
        }
        return dp[amount] > amount ? -1 : dp[amount];
    }
}

16. LRU 缓存

146. LRU 缓存 2022.8.8

class LRUCache {
    int cap;
    LinkedHashMap<Integer, Integer> cache = new LinkedHashMap<>();
    public LRUCache(int capacity) {
        this.cap = capacity;
    }

    public int get(int key) {
        if (!cache.containsKey(key)) {
            return -1;
        }
        // 将 key 变为最近使用
        makeRecently(key);
        return cache.get(key);
    }

    public void put(int key, int val) {
        if (cache.containsKey(key)) {
            // 修改 key 的值
            cache.put(key, val);
            // 将 key 变为最近使用
            makeRecently(key);
            return;
        }

        if (cache.size() >= this.cap) {
            // 链表头部就是最久未使用的 key
            int oldestKey = cache.keySet().iterator().next();
            cache.remove(oldestKey);
        }
        // 将新的 key 添加链表尾部
        cache.put(key, val);
    }

    private void makeRecently(int key) {
        int val = cache.get(key);
        // 删除 key,重新插入到队尾
        cache.remove(key);
        cache.put(key, val);
    }
}
// 详细解析参见:
// https://labuladong.github.io/article/?qno=146

17. 打家劫舍

198. 打家劫舍

class Solution {
    public int rob(int[] nums) {
        if(nums.length == 0)
            return 0;
        int [] dp = new int[nums.length];
        dp[0] = nums[0];
        // 每次做数组判定时都需要做数组边界判定,防止越界
        if(nums.length < 2)
            return nums[0];
        dp[1] = (nums[0]>nums[1]) ? nums[0] : nums[1];
        for(int i = 2; i<nums.length; i++)
            dp[i] = ((nums[i] + dp[i-2]) > dp[i-1]) ? (nums[i]+dp[i-2]) : dp[i-1];
        return dp[nums.length-1];
    }
}

18. 二叉树的右视图

199. 二叉树的右视图

class Solution {
    List<Integer> res = new ArrayList<>();
    // 记录递归的层数
    int depth = 0;

    public List<Integer> rightSideView(TreeNode root) {
        traverse(root);
        return res;
    }

    // 二叉树遍历函数
    void traverse(TreeNode root) {
        if (root == null) {
            return;
        }
        // 前序遍历位置
        depth++;
        if (res.size() < depth) {
            // 这一层还没有记录值
            // 说明 root 就是右侧视图的第一个节点
            res.add(root.val);
        }
        // 注意,这里反过来,先遍历右子树再遍历左子树
        // 这样首先遍历的一定是右侧节点
        traverse(root.right);
        traverse(root.left);
        // 后序遍历位置
        depth--;
    }
}

19. 二叉树的完全性检验

958. 二叉树的完全性检验

class Solution {
    public boolean isCompleteTree(TreeNode root) {
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        // 遍历完所有非空节点时变成 true
        boolean end = false;
        // while 循环控制从上向下一层层遍历
        while (!q.isEmpty()) {
            int sz = q.size();
            // for 循环控制每一层从左向右遍历
            for (int i = 0; i < sz; i++) {
                TreeNode cur = q.poll();
                if (cur == null) {
                    // 第一次遇到 null 时 end 变成 true
                    // 如果之后的所有节点都是 null,则说明是完全二叉树
                    end = true;
                } else {
                    if (end) {
                        // end 为 true 时遇到非空节点说明不是完全二叉树
                        return false;
                    }
                    // 将下一层节点放入队列,不用判断是否非空
                    q.offer(cur.left);
                    q.offer(cur.right);
                }
            }
        }
        return true;
    }
}

20. 航班预订统计【华子】

1109. 航班预订统计 2022.8.10
写法一:

// 差分数组
class Solution {
    public int[] corpFlightBookings(int[][] bookings, int n) {
        int[] res = new int[n];
        Difference df = new Difference(res);

        for (int[] booking : bookings) {
            int i = booking[0] - 1;
            int j = booking[1] - 1;
            int val = booking[2];

            df.increment(i, j, val);
        }

        return df.result();
    }

    class Difference {
        private int[] diff;

        public Difference(int[] nums) {
            assert nums.length > 0;
            diff = new int[nums.length];
            diff[0] = nums[0];
            for (int i = 1; i < nums.length; i++) {
                diff[i] = nums[i] - nums[i - 1];
            }
        }

        public void increment(int i, int j, int val) {
            diff[i] += val;
            if (j + 1 < diff.length) {
                diff[j + 1] -= val;
            }
        }

        public int[] result() {
            int[] res = new int[diff.length];
            res[0] = diff[0];
            for (int i = 1; i < diff.length; i++) {
                res[i] = res[i - 1] + diff[i];
            }
            return res;
        }
    }
}

写法二:

class Solution {
    public int[] corpFlightBookings(int[][] bookings, int n) {
        int[] res = new int[n];
        int[] diff = new int[n];

        for (int[] booking : bookings) {
            int i = booking[0] - 1;
            int j = booking[1] - 1;
            int val = booking[2];

            for (int k = i; k <= j; k++) {
                diff[k] += val;
            }
        }
        return diff;
    }

写法三:

class Solution {
    public int[] corpFlightBookings(int[][] bookings, int n) {
        int[] res = new int[n];
        int[] diff = new int[n];

        for (int[] booking : bookings) {
            int i = booking[0] - 1;
            int j = booking[1] - 1;
            int val = booking[2];

            diff[i] += val;
            if (j + 1 < n) {
                diff[j + 1] -= val;
            }
        }

        res[0] = diff[0];
        for (int i = 1; i < n; i++) {
            res[i] = res[i - 1] + diff[i];
        }

        return res;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心海非海_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值