腾讯面试高频算法题

LRU 缓存

146. LRU 缓存 - 力扣(LeetCode)

java 复制代码
class LRUCache {

    private int capacity;
    private Map<Integer, Integer> map = new LinkedHashMap<>();

    public LRUCache(int capacity) {
        this.capacity = capacity;
    }
    
    public int get(int key) {
        Integer value = map.remove(key);
        if(value != null){ //key已存在,更新value
            map.put(key, value);
            return value;
        }
        return -1;
    }
    
    public void put(int key, int value) {
        Integer val = map.remove(key);
        if(val != null){//key存在
            map.put(key, value);
            return;
        }
        //如果不存在,当前key压根就没被发现,所以容量还是capacity
        if(map.size() == capacity){
            int index = map.keySet().iterator().next();//找到迭代器的第一个元素
            map.remove(index);
        }
        map.put(key, value);
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

LFU 缓存

460. LFU 缓存 - 力扣(LeetCode)

java 复制代码
class LFUCache {

    private final int capacity;
    private final Map<Integer, Integer> keyToFreq = new HashMap<>();
    private final Map<Integer, Map<Integer, Integer>> freqToMap = new HashMap<>();
    private int minFreq;

    public LFUCache(int capacity) {
        this.capacity = capacity;
    }
    
    public int get(int key) {
        return move(key, null);
    }
    
    public void put(int key, int value) {
        if(move(key, value) != -1){
            return;
        }
        if(keyToFreq.size() == capacity){
            Map<Integer, Integer> map = freqToMap.get(minFreq);
            Integer oldestKey = map.keySet().iterator().next();
            map.remove(oldestKey);
            keyToFreq.remove(oldestKey);
        }

        keyToFreq.put(key, 1);
        freqToMap.computeIfAbsent(1, k -> new LinkedHashMap<>()).put(key, value);
        minFreq = 1;
    }
    //把key从第freq摞书中抽出来,放到第freq+1摞书的最上面
    //返回key对应的value
    public int move(Integer key, Integer value){
        Integer freq = keyToFreq.getOrDefault(key, null);
        if(freq == null){
            return - 1;
        }
        Map<Integer, Integer> map = freqToMap.get(freq);
        Integer v = map.remove(key);
        if(value == null){
            value = v;
        }
        if(map.size() == 0 && minFreq == freq){
            minFreq++;
        }
        keyToFreq.merge(key, 1, Integer::sum);

        freqToMap.computeIfAbsent(freq + 1, k -> new LinkedHashMap<>()).put(key, value);
        return value;
    }
}

/**
 * Your LFUCache object will be instantiated and called as such:
 * LFUCache obj = new LFUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

带 TTL 的 LRU

java 复制代码
package mianshi;

import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Cache {

    private final int capacity;
    private final int ttl;
    private final LinkedHashMap<Integer, Integer> cache;
    private final Map<Integer, Integer> expireTimes;


    public Cache(int capacity, int ttl){
        this.capacity = capacity;
        this.ttl = ttl;
        this.cache = new LinkedHashMap<>();
        this.expireTimes = new HashMap<>();

        startAutoCleaner();
    }

    public int get(int key){
        Integer value = cache.remove(key);
        if(value == null){
            return -1;
        }

        //有这个元素
        cache.put(key, value);
        expireTimes.put(key, (int)(System.currentTimeMillis() / 1000) + ttl); //更新元素的过期时间
        return value;
    }

    public void put(int key, int value){
        Integer v = cache.remove(key);
        if(v != null){//已存在的元素
            cache.put(key, value);
            expireTimes.put(key, (int)(System.currentTimeMillis() / 1000) + ttl);
            return;
        }
        //不存在的元素,要put新元素
        if(cache.size() == capacity){
            Integer index = cache.keySet().iterator().next();
            cache.remove(index);
            expireTimes.remove(index);
        }
        cache.put(key, value);
        expireTimes.put(key, (int)(System.currentTimeMillis() / 1000) + ttl);
    }

    public void startAutoCleaner(){
        ScheduledExecutorService cleaner = Executors.newSingleThreadScheduledExecutor();

        //固定频率的任务
        cleaner.scheduleAtFixedRate(
                () -> {
                    int currentTime = (int)(System.currentTimeMillis() / 1000);
                    expireTimes.keySet().removeIf(
                            key ->{
                                if(currentTime > expireTimes.get(key)){
                                    cache.remove(key);
                                    expireTimes.remove(key);
                                    return true;
                                }
                                return false;
                            }
                    );
                },
                0,
                1,
                TimeUnit.SECONDS
        );
    }



}

最长递增子序列

300. 最长递增子序列 - 力扣(LeetCode)

java 复制代码
class Solution {
    public int lengthOfLIS(int[] nums) {
        int n = nums.length;
        int[] dp = new int[n + 1]; //至少是1
        Arrays.fill(dp, 1);
        //dp[i]表示以i为结尾的最长递增子序列长度
        //对于每个选定的字符都需要验证在他前面的字符都是小于此字符的,只有如此才能接上上一个子序列
        int ans = 0;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= i; j++){
                if(nums[i - 1] > nums[j - 1]){
                    dp[i] = Math.max(dp[j] + 1, dp[i]);//要么当前字符大于前面字符可以接上,要么从现在开始
                }
            }
            ans = Math.max(ans, dp[i]);
        }

        return ans;
    }
}

合并两个升序链表

21. 合并两个有序链表 - 力扣(LeetCode)

java 复制代码
/**
 * 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 mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode dummy = new ListNode(0);
        ListNode cur = dummy;
        while(list1 != null && list2 != null){
            if(list1.val <= list2.val){
                cur.next = new ListNode(list1.val);
             
                list1 = list1.next;
            }else{
                cur.next = new ListNode(list2.val);
                
                list2 = list2.next;
            }
            cur = cur.next;
        }
        //单独处理两个
        cur.next = (list1 != null) ? list1 : list2; 
         

        return dummy.next;
    }
}

数组中第 k 个最大元素

215. 数组中的第K个最大元素 - 力扣(LeetCode)

java 复制代码
class Solution {
    public int findKthLargest(int[] nums, int k) {
        ArrayList<Integer> list = new ArrayList<>();
        for(int i : nums){
            list.add(i);
        }

        return maxSerach(list, k);
    }

    public int maxSerach(ArrayList<Integer> list, int k){
        int n = list.size();
        Random r = new Random();
        int pivot = list.get(r.nextInt(n));
        
        ArrayList<Integer> small = new ArrayList<>();
        ArrayList<Integer> equal = new ArrayList<>();
        ArrayList<Integer> big = new ArrayList<>();

        for(int num : list){
            if(num > pivot) big.add(num);
            else if(num < pivot) small.add(num);
            else equal.add(num);
        }

        if(k <= big.size()){
            return maxSerach(big, k);
        }

        if(n - k < small.size()){
            return maxSerach(small, k - n + small.size());
        }

        return pivot;
    }
}

打家劫舍

198. 打家劫舍 - 力扣(LeetCode)

java 复制代码
class Solution {
    public int rob(int[] nums) {
        int n = nums.length;
        if(n == 1) return nums[0];
        int[] dp = new int[n + 1];
        dp[0] = 0;
        dp[1] = nums[0];

        //当前偷窃的最大金额是要么是这个屋的现金,要么是前两个屋+现在的金额 
        for(int i = 2; i <= n; i++){
            dp[i] = Math.max(dp[i - 2] + nums[i - 1], dp[i - 1]);
            
        }
        return dp[n];
    }
}

最长有效括号

32. 最长有效括号 - 力扣(LeetCode)

java 复制代码
class Solution {
    public int longestValidParentheses(String s) {
        int n = s.length();
        char[] chars = s.toCharArray();
        int maxLen = 0;
        Deque<Integer> st = new ArrayDeque<>();
        st.push(-1);
        for(int i = 0; i < n; i++){
            if(chars[i] == '('){
                st.push(i);
            }else{
                st.pop();
                if(st.isEmpty()){
                    st.push(i);
                }else{
                    maxLen = Math.max(maxLen, i - st.peek());
                }
            }
        }

        return maxLen;
    }
}

合并区间

56. 合并区间 - 力扣(LeetCode)

java 复制代码
class Solution {
    public int[][] merge(int[][] intervals) {
        Arrays.sort(intervals, (p, q) -> (p[0] - q[0]));

        List<int[]> list = new ArrayList<>();
        for(int[] num : intervals){
            int m = list.size();
            if(m > 0 && list.get(m - 1)[1] >= num[0]){
                list.get(m - 1)[1] = Math.max(list.get(m - 1)[1], num[1]);
            }else{
                list.add(num);
            }
        }

        return list.toArray(new int[list.size()][]);
    }
}

分隔链表

86. 分隔链表 - 力扣(LeetCode)

java 复制代码
/**
 * 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 partition(ListNode head, int x) {
        ListNode bigDummy = new ListNode(0);
        ListNode smallDummy = new ListNode(0);
        ListNode big = bigDummy;
        ListNode small = smallDummy;
        while(head != null){
            if(head.val < x){
                small.next = head;
                small = small.next;
            }else{
                big.next = head;
                big = big.next;
            }
            head = head.next;
        }
        big.next = null;//重要
        small.next = bigDummy.next;
        
        return smallDummy.next;
    }
}

寻找峰值

162. 寻找峰值 - 力扣(LeetCode)

java 复制代码
class Solution {
    public int findPeakElement(int[] nums) {
        int l = 0;
        int r = nums.length - 1;
        while(l < r){
            int mid = (l + r) / 2;
            if(nums[mid] < nums[mid + 1]) l = mid + 1;
            else r = mid;
        }
        
        return l;
    }
}

字符串相加

java 复制代码
class Solution {
    public String addStrings(String num1, String num2) {
        StringBuilder sb = new StringBuilder("");
        int n = num1.length() - 1;
        int m = num2.length() - 1;
        int carry = 0;
        while(n >= 0 || m >= 0){
            int a = n >= 0 ? num1.charAt(n) - '0' : 0;
            int b = m >= 0 ? num2.charAt(m) - '0' : 0;
            int res = (a + b + carry) % 10;
            carry = (a + b + carry) / 10;
            sb.append(res); 
            n--;
            m--;
        }
        if(carry == 1) sb.append(1);
        return sb.reverse().toString();
    }
}

反转字符串中的单词

151. 反转字符串中的单词 - 力扣(LeetCode)

java 复制代码
class Solution {
    public String reverseWords(String s) {
        StringBuilder sb = new StringBuilder("");
        List<String> list = new ArrayList<>();
        StringBuilder ss = new StringBuilder("");
        for(int i = 0; i < s.length(); i++){
            if(s.charAt(i) != ' '){
                ss.append(s.charAt(i));
            }else{
                if(ss.length() != 0 && ss != null){
                    list.add(ss.toString());
                    ss.setLength(0);
                }   
            }
        }
        if(ss.length() != 0 && ss != null) list.add(ss.toString());
        for(int i = list.size() - 1; i >= 0; i--){
            if(i != 0){
                sb.append(list.get(i));
                sb.append(" ");
            }else{
                sb.append(list.get(i));
            }
        }

        return sb.toString();
    }
}
java 复制代码
class Solution {
    public String reverseWords(String s) {
        s = s.trim();
        int i = s.length() - 1, j = i;
        StringBuilder sb = new StringBuilder();
        while(i >= 0){
            while(i >= 0 && s.charAt(i) != ' ') i--;//找到第一个空格
            sb.append(s.substring(i + 1, j + 1) + ' ');
            while(i >= 0 && s.charAt(i) == ' ') i--;
            j = i; //j是下一个单次的末尾坐标
        }

        return sb.toString().trim();
    }
}

最小覆盖子串

76. 最小覆盖子串 - 力扣(LeetCode)

java 复制代码
class Solution {
    public String minWindow(String s, String t) {
        int[] cntS = new int[128];
        int[] cntT = new int[128];
        for(char a : t.toCharArray()){
            cntT[a]++;
        }

        int left = 0;
        int ansLeft = - 1;//ansleft+ansright=s.length()
        int ansRight = s.length() - 1;
        char[] chars = s.toCharArray();
        for(int right = 0; right < s.length(); right++){
            cntS[chars[right]]++;//进入窗口
            while(converted(cntS, cntT)){ //如果当前字串满足题意,计算当前字串的长度
                if(right - left < ansRight - ansLeft){
                    ansLeft = left;
                    ansRight = right;
                }
                //尝试剔除左侧窗口字符
                cntS[chars[left]]--;
                left++;
            }
            
        }

        return ansLeft == - 1 ? "" : s.substring(ansLeft, ansRight + 1);
    }

    public boolean converted(int[] cntS, int[] cntT){
        for(int i = 'a'; i <= 'z'; i++){
            if(cntS[i] < cntT[i]){
                return false;
            }
        }
        for(int i = 'A'; i <= 'Z'; i++){
            if(cntS[i] < cntT[i]){
                return false;
            }
        }

        return true;
    }
}

反转链表

206. 反转链表 - 力扣(LeetCode)

java 复制代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode cur = head;
        ListNode pre = null;
        while(cur != null){
            ListNode tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }

        return pre;
    }
}

回文链表

234. 回文链表 - 力扣(LeetCode)

java 复制代码
/**
 * 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 boolean isPalindrome(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
        }
        ListNode back = reverseList(slow);
        ListNode cur = head;
        while(cur !=  null && back != null){
            if(back.val != cur.val){
                return false;
            }
            cur = cur.next;
            back = back.next;
        }

        return true;
    }

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

        return pre;
    }
}

在排序数组中查找一个元素的第一个和最后一个位置

34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)

java 复制代码
class Solution {
    public int[] searchRange(int[] nums, int target) {
        int l = 0;
        int r = nums.length - 1;
        while(l <= r){
            int mid = l + r >>> 1;
            if(nums[mid] >= target){
                r = mid - 1;
            }else{
                l = mid + 1;
            }
        }
        if(l == nums.length || nums[l] != target) return new int[]{-1, -1};
        int begin = l;
        while(l < nums.length && nums[l] == target)l++;
        return new int[]{begin, l - 1};
    }
}

合并两个有序数组

88. 合并两个有序数组 - 力扣(LeetCode)

java 复制代码
class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int i = m - 1;
        int j = n - 1;
        int index = n + m - 1;
        while(index >= 0 && i >= 0 && j >= 0){
            if(nums1[i] >= nums2[j]){
                nums1[index] = nums1[i];
                i--;
            }else{
                nums1[index] = nums2[j];
                j--;
            }
            index--;
        }
        while(j >= 0){
            nums1[index] = nums2[j];
            index--;
            j--;
        }
    }
}

滑动窗口最大值

239. 滑动窗口最大值 - 力扣(LeetCode)

java 复制代码
class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        Deque<Integer> dq = new ArrayDeque<>();
        int n = nums.length;
        int[] ans = new int[n - k + 1]; 
        for(int right = 0; right < n; right++){
            while(!dq.isEmpty() && nums[dq.getLast()] <= nums[right]){
                dq.removeLast();
            }
            dq.addLast(right);
            int left = right - k + 1;
            if(left > dq.getFirst()){
                dq.removeFirst();
            }
            if(left >= 0){
                ans[left] = nums[dq.getFirst()];
            }
        }

        return ans;
    }
}

编辑距离

72. 编辑距离 - 力扣(LeetCode)

java 复制代码
class Solution {
    public int minDistance(String word1, String word2) {
        int n = word1.length();
        int m = word2.length();
        int[][] dp = new int[n + 1][m + 1];//dp[i][j]表示从i转换到j所需要的最少操作数
        //预处理边界为,某个单词长度为0
        for(int i = 1; i <= n; i++) dp[i][0] = dp[i - 1][0] + 1;
        for(int j = 1; j <= m; j++) dp[0][j] = dp[0][j - 1] + 1;
        int ans = 0;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                if(word1.charAt(i - 1) == word2.charAt(j - 1)) dp[i][j] = dp[i - 1][j - 1];
                else dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
            }
        }
        return dp[n][m];
    }
}

无重复字符的最长子串

3. 无重复字符的最长子串 - 力扣(LeetCode)

java 复制代码
class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s == null || s.length() == 0) return 0;
        int n = s.length();
        int[] cnt = new int[128];
        int len = 0;
        int left = 0;
        char[] chars = s.toCharArray();
        for(int right = 0; right < n; right++){
            cnt[chars[right]]++;
            while(cnt[chars[right]] > 1){
                cnt[chars[left]]--;
                left++;
 
            }
            
            len = Math.max(right - left + 1, len);
        }
        return len;

    }
}

有效的括号

20. 有效的括号 - 力扣(LeetCode)

java 复制代码
class Solution {
    public boolean isValid(String s) {
        if(s.length() % 2 != 0) return false;
        Map<Character, Character> mp = new HashMap<>();
        mp.put('(', ')');
        mp.put('[', ']');
        mp.put('{', '}');
        Deque<Character> q = new ArrayDeque<>();
        char[] chars = s.toCharArray();
        for(int i = 0; i < s.length(); i++){
            if(mp.containsKey(chars[i])){
                q.addLast(chars[i]); //如果是左括号,直接插入
            }else{ //遇到右括号,弹出栈顶元素,对比是否匹配

                if(mp.get(q.getLast()) != chars[i]){
                    return false;
                }
                q.removeLast();
            }
        }
        if(!q.isEmpty()) return false;

        return true;
    }
}

用 Rand7()实现 Rand10()

470. 用 Rand7() 实现 Rand10() - 力扣(LeetCode)

使用 rand7(),首先尝试扩大范围,因为 1-7 无法生成 1-10 的内容,所以我们给 rand7() *7,现在的范围是不连续的 7 个数,7,14,21,28,35,42,49,需要加 rand7()补上这些区间的空缺,但是现在有个问题就是 1-6 没法得到,所以给 (rand7() - 1) * 7,缩小一下范围,0, 7,14,21,28,35,42,此时+rand7(),把大于 40 的全部拒绝,每个数字的概率都是 4/49。

java 复制代码
/**
 * The rand7() API is already defined in the parent class SolBase.
 * public int rand7();
 * @return a random integer in the range 1 to 7
 */
class Solution extends SolBase {
    public int rand10() {
        while(true){
            int a = rand7();
            int b = rand7();
            int num = (a - 1) * 7 + b;

            if(num <= 40) return (num - 1) % 10 + 1;
        }

        
    }
}
java 复制代码
/**
 * The rand7() API is already defined in the parent class SolBase.
 * public int rand7();
 * @return a random integer in the range 1 to 7
 */
class Solution extends SolBase {
    public int rand10() {
        while(true){
            int a = rand7();
            int b = rand7();
            int num = (a - 1) * 7 + b;

            if(num <= 40) return (num - 1) % 10 + 1;
            else{
                // 1-9
                int newNum = (num - 41) * 7 + rand7();
                if(newNum <= 60) return (newNum - 1) % 10 + 1;
            }
        }

        
    }
}

寻找重复数

287. 寻找重复数 - 力扣(LeetCode)

链表的结构是:节点+next 指针

在这个题目中,节点可以理解为是当前下标,next 指针指向的是 numsi,基于此可以把数组转化为链表,这个题目就变成了寻找链表成环的入口。

慢指针的路程:a+x

快指针的路程:a+x+n*环长

快指针速度是慢指针的两倍:相遇时

2(a+x) = a + x + n*环长

a = n* 环长-x

a = 环长-x

所以起点到入口的距离=相遇点到入口的距离

所以再搞一个指针,两个指针同时走,下次相遇就是重复点

java 复制代码
class Solution {
    public int findDuplicate(int[] nums) {
        int slow = 0;
        int fast = 0;

        while(true){
            slow = nums[slow];
            fast = nums[nums[fast]];
            if(fast == slow) break; //相遇点
        }

        slow = 0;
        while(slow != fast){
            slow = nums[slow];
            fast = nums[fast];
        }
        return slow;
    }
}

排序数组(手撕快排)

912. 排序数组 - 力扣(LeetCode)

java 复制代码
class Solution {

    private static final Random ran = new Random();

    public int[] sortArray(int[] nums) {
        quickSort(nums, 0, nums.length - 1);
        return nums;
    }

    public void quickSort(int[] nums, int l, int r){
        boolean ordered = true;
        for(int i = l; i < r; i++){
            if(nums[i] > nums[i + 1]){
                ordered = false;
                break;
            }
        }
        if(ordered) return; //已经有序了

        int mid = partition(nums, l, r); //分区找到pivot
        quickSort(nums, l, mid - 1);
        quickSort(nums, mid + 1, r);

    }

    public int partition(int[] nums, int l, int r){
        int i = l + ran.nextInt(r - l + 1);
        int pivot = nums[i];
        swap(nums, i, l);

        i = l + 1;
        int j = r;
        while(true){
            while(i <= j && nums[i] < pivot) i++;//找到大于pivot的
            while(i <= j && nums[j] > pivot) j--;//找到小于pivot的

            if(i >= j) break;
            swap(nums, i, j);
            i++;
            j--;
        }
        swap(nums, l, j);
        return j;
    }

    public void swap(int[] nums, int l, int r){
        int tmp = nums[l];
        nums[l] = nums[r];
        nums[r] = tmp;
    }
}

二分查找

704. 二分查找 - 力扣(LeetCode)

java 复制代码
class Solution {
    public int search(int[] nums, int target) {
        int l = 0;
        int r = nums.length - 1;
        while(l <= r){
            int mid = (l + r) / 2;
            if(nums[mid] < target) l = mid + 1;
            else if(nums[mid] > target) r = mid - 1;
            else return mid;
        }

        return -1;
    }
}

最大子数组和

53. 最大子数组和 - 力扣(LeetCode)

java 复制代码
class Solution {
    public int maxSubArray(int[] nums) {
        int[] dp = new int[nums.length + 1];
        int maxSum = nums[0];
        
        for(int i = 1; i <= nums.length; i++){
            dp[i] = Math.max(dp[i - 1] + nums[i - 1], nums[i - 1]);
            maxSum = Math.max(dp[i], maxSum);
        }

        return maxSum;
    }
}

寻找两个正序数组的中位数

4. 寻找两个正序数组的中位数 - 力扣(LeetCode)

java 复制代码
class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int n = nums1.length;
        int m = nums2.length;
        int[] nums = new int[n + m];
        int index = 0;
        int i = 0;
        int j = 0;
        while(i < n && j < m){
            if(nums1[i] <= nums2[j]){
                nums[index] = nums1[i];
                i++;
            }else{
                nums[index] = nums2[j];
                j++;
            }
            index++;
        }
        while(i < n){
            nums[index] = nums1[i];
            i++;
            index++;
        } 
        while(j < m){
            nums[index] = nums2[j];
            j++;
            index++;
        }   
        
        return (n + m) % 2 != 0 ? 1.0 * nums[(n+m) / 2] : 1.0 *(nums[(n + m) / 2] + nums[(n + m) / 2 - 1]) / 2;        

    }
}

颜色分类

75. 颜色分类 - 力扣(LeetCode)

先把全部颜色当成 2,再把应该是 1 的覆盖回来,把应该是 0 的覆盖掉。

java 复制代码
class Solution {
    public void sortColors(int[] nums) {
        int p0 = 0; //放0的位置
        int p1 = 0; //放1的位置
        for(int i = 0; i < nums.length; i++){
            int x = nums[i];
            nums[i] = 2;
            if(x <= 1) nums[p1++] = 1;
            if(x == 0) nums[p0++] = 0;

        }
    }
}

通配符匹配

44. 通配符匹配 - 力扣(LeetCode)

java 复制代码
class Solution {
    public boolean isMatch(String s, String p) {
        int n = s.length();
        int m = p.length();

        boolean[][] dp = new boolean[n + 1][m + 1]; //表示前i位和j位字符匹配
        dp[0][0] = true;

        //如果输入s是空串
        for(int j = 1; j <= m; j++){
            if(p.charAt(j - 1) == '*'){
                dp[0][j] = dp[0][j - 1];
            }
        }

        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                if(p.charAt(j - 1) == '?' || s.charAt(i - 1) == p.charAt(j - 1)){ //第j位是?表示可以随便匹配s
                    dp[i][j] = dp[i - 1][j - 1];
                }else if(p.charAt(j - 1) == '*'){
                    //不包含*        相当于包含*,但是跟i的前一位比,因为*本身就可以替代
                    dp[i][j] = dp[i][j - 1] || dp[i - 1][j];
                }
            }
        }

        return dp[n][m];
    }
}

删除排序链表的重复元素

83. 删除排序链表中的重复元素 - 力扣(LeetCode)

java 复制代码
/**
 * 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) {
        ListNode dummy = head;
        ListNode cur = head;

        while(cur != null && cur.next != null){
            if(cur.val == cur.next.val){
                cur.next = cur.next.next;
            }else cur = cur.next;
        }

        return dummy;
    }
}

删除链表中的重复元素 II

82. 删除排序链表中的重复元素 II - 力扣(LeetCode)

java 复制代码
/**
 * 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) {
        ListNode dummy = new ListNode(0, head);
        ListNode cur = dummy;

        while(cur.next != null && cur.next.next != null){

            if(cur.next.val == cur.next.next.val){
                int x = cur.next.val;
                while(cur.next != null && cur.next.val == x){
                    cur.next = cur.next.next;
                }
            }else{
                cur = cur.next;
            }
        }

        return dummy.next;
    }
}

最小覆盖子串

76. 最小覆盖子串 - 力扣(LeetCode)

java 复制代码
class Solution {
    public String minWindow(String s, String t) {
        int[] cntS = new int[128];
        int[] cntT = new int[128];
        char[] cs = s.toCharArray();
        char[] ct = t.toCharArray();

        for(char c : ct) cntT[c]++;
        int left = 0;
        int ansLeft = -1;
        int ansRight = -1;
        int minLen = Integer.MAX_VALUE;
        for(int right = 0; right < cs.length; right++){
            cntS[cs[right]]++;
            while(converted(cntS, cntT)){
                if(right - left + 1 < minLen){
                    minLen = right - left + 1;
                    ansLeft = left;
                    ansRight = right;
                }
                cntS[cs[left]]--;
                left++;
            }
        }
        return ansLeft == -1 ? "" : s.substring(ansLeft, ansRight + 1);
    }

    public boolean converted(int[] cntS, int[] cntT){
        for(int i = 'a'; i <= 'z'; i++){
            if(cntS[i] < cntT[i]) return false;
        }
        for(int i = 'A'; i <= 'Z'; i++){
            if(cntS[i] < cntT[i]) return false;
        }
        return true;
    }
}

数组中重复的数据(重要)

442. 数组中重复的数据 - 力扣(LeetCode)

java 复制代码
class Solution {
    public List<Integer> findDuplicates(int[] nums) {
        //因为所有整数都在[1,n]内,所以每个整数都可以当作数组下标,把访问过的整数标为负数,下次如果再次访问到负数,说明当前位置被重复访问,也就是数组中数据重复
        List<Integer> ans = new ArrayList<>();
        for(int i = 0; i < nums.length; i++){
            int x = Math.abs(nums[i]);//获取整数值当作下标
            int index = x -1;
            if(nums[index] < 0) ans.add(x); //查看下标位置是否为负数
            else nums[index] = -nums[index];
            
        }
        return ans;
    }
}

最接近的三数之和

16. 最接近的三数之和 - 力扣(LeetCode)

java 复制代码
class Solution {
    public int threeSumClosest(int[] nums, int target) {
        int ans = 0;
        int diff = Integer.MAX_VALUE;
        for(int i = 0; i < nums.length; i++){
            for(int j = i + 1; j < nums.length; j++){
                for(int k = j + 1; k < nums.length; k++){
                    int sum = nums[i] + nums[j] + nums[k];
                    if(Math.abs(sum - target) < diff){
                        diff = Math.abs(sum - target);
                        ans = sum;
                    }
                }
            }
        }
        return ans;
    }
}
java 复制代码
class Solution {
    public int threeSumClosest(int[] nums, int target) {
        int n = nums.length;
        int diff = Integer.MAX_VALUE;
        int ans = 0;
        Arrays.sort(nums);
        for(int i = 0; i < n - 2; i++){
            if(i > 0 && nums[i] == nums[i - 1]) continue;
            int l = i + 1;
            int r = n - 1;
            while(l < r){
                int sum = nums[i] + nums[l] + nums[r];
                if(sum == target) return target;

                if(Math.abs(sum - target) < diff){
                    diff = Math.abs(sum - target);
                    ans = sum;
                }

                if(sum > target) r--;
                else l++;
            }
        }
        return ans;
    }
}

三数之和

15. 三数之和 - 力扣(LeetCode)

java 复制代码
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> ans = new ArrayList<>();
        int n = nums.length;
        Arrays.sort(nums);
        for(int i = 0; i < n - 2; i++){
            if(i > 0 && nums[i] == nums[i - 1]) continue;
            if(nums[i] + nums[i + 1] + nums[i + 2] > 0) break;
            if(nums[i] + nums[n - 2] + nums[n - 1] < 0) continue;

            int l = i + 1;
            int r = n - 1;
            while(l < r){
                if(nums[i] + nums[l] + nums[r] > 0){
                    r--;
                }else if(nums[i] + nums[l] + nums[r] < 0){
                    l++;
                }else{
                    ans.add(List.of(nums[i], nums[l], nums[r]));
                    for(l++; l < r && nums[l] == nums[l - 1]; l++);
                    for(r--; l < r && nums[r] == nums[r + 1]; r--);
                }
            }
        }

        return ans;
    }
}

和为 s 的连续正数序列

LCR 180. 文件组合 - 力扣(LeetCode)

文件编号就是自然数序列 1, 2, 3, 4, 5, 6,...,找出和为 target 的组合。

java 复制代码
class Solution {
    public int[][] fileCombination(int target) {
        List<int[]> ans = new ArrayList<>();
        int l = 1;
        int preSum = 0;
        for(int r = 1; r <= target - 1; r++){
            preSum += r;
            while(preSum > target){
                preSum -= l;
                l++;
            }
            if(preSum == target){
                int[] list = new int[r - l + 1];
                for(int i = l; i <= r; i++){
                    list[i - l] = i; 
                }
                ans.add(list);
            }
        }
        return ans.toArray(new int[ans.size()][]);
    }
}

两两交换链表中的节点

24. 两两交换链表中的节点 - 力扣(LeetCode)

java 复制代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        if(head == null || head.next == null) return head;

        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode cur = dummy;

        while(cur.next != null && cur.next.next != null){
            ListNode node1 = cur.next;
            ListNode node2 = cur.next.next;

            cur.next = node2; //node2现在是头节点
            node1.next = node2.next; //让 node1 指向后面的节点,防止断链
            node2.next = node1;//让 node2 指向 node1,完成反转
            
            cur = node1;
           
        }

        return dummy.next;
    }
}

ip 地址转化为 10 进制整数

192.168.1.1

由于每一位都是 0-255,所以用 8 位二进制表示,相当于 192 左移 24 位,168 左移 16 位,1 左移 8 位,1 不移。

java 复制代码
import java.util.*;

public class Althoriom {
    public static void main(String[] args) {
        String ip = "10.0.3.193";
        System.out.println(ipToInt(ip));
    }

    public static long ipToInt(String ip){
        long ans = 0;
        String[] part = ip.split("\\."); //反斜杠 \\用来转义
        for(int i = 0; i < 4; i++){
            long res = Long.parseLong(part[i]);

            ans |= (res << (24 - 8 * i));
        }
        return ans;
    }
}

复原 IP 地址

93. 复原 IP 地址 - 力扣(LeetCode)

java 复制代码
class Solution {

    private List<String> ans = new ArrayList<>();

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

    public void backtrack(String s, int start, List<String> tmp){
        if(tmp.size() == 4){
            if(start == s.length()){
                ans.add(String.join(".", tmp));
                return;
            }
        }
        for(int len = 1; len <= 3; len++){
            if(start + len > s.length()) break;
            String str = s.substring(start, start + len);

            if(isValid(str)){
                tmp.add(str);
                backtrack(s, start + len, tmp);
                tmp.remove(tmp.size() - 1);
            }
        }

    }

    public boolean isValid(String str){
        if(str.length() > 1 && str.charAt(0) == '0') return false;
        int num = 0;
        for(int i = 0; i < str.length(); i++){
            num = num * 10 + str.charAt(i) - '0'; 
        }
        return num >= 0 && num <= 255;
    }
}

前 K 个高频单词

692. 前K个高频单词 - 力扣(LeetCode)

java 复制代码
class Solution {
    public List<String> topKFrequent(String[] words, int k) {
        Map<String,Integer> map = new HashMap<>();
        for(int i = 0; i < words.length; i++){
            map.put(words[i], map.getOrDefault(words[i], 0) + 1);
        }
        PriorityQueue<String> pq = new PriorityQueue<>(
                (p, q) -> {
                    int countP = map.get(p);
                    int countQ = map.get(q);

                    if(countP != countQ){
                        return countQ - countP;
                    }

                    return p.compareTo(q);
                }

        ); //大根堆
        for (String s : map.keySet()) {
            pq.offer(s);
        }

        List<String> ans = new ArrayList<>();
        for(int i = 0; i < k; i++){
            ans.add(pq.poll());
        }

        return ans;
    }
}
相关推荐
珂朵莉MM1 小时前
第七届全球校园人工智能算法精英大赛-算法巅峰赛产业命题赛第3赛季优化题--整数线性规划
人工智能·算法
于先生吖1 小时前
Java消息队列优化抢单逻辑,同城搬家拉货多场景业务数据库架构设计
java·开发语言·数据库架构
小谢小哥1 小时前
68-持续集成详解
java·后端·架构
用户925807911481 小时前
redission原理
java·后端
小则又沐风a1 小时前
今日算法----一篇文章学会背包问题
运维·服务器·算法
小旭95271 小时前
Spring Cloud 集成分布式日志 ELK+Swagger 接口文档实战
java·分布式·后端·elk·spring cloud
屋外雨大,惊蛰出没1 小时前
spring boot+mybatis开发基础复习
java·spring boot·后端
这个DBA有点耶1 小时前
死锁排查进阶:从日志到根因的完整分析链
java·开发语言·数据库·sql·运维开发·学习方法·dba