经典算法题汇总

目录

1. 动态规划 / 回溯

1.1 最长公共子序列(牛客版, leetcode 1143)

1.2 最长上升子序列(leetcode 300)

1.3 最长回文子串(牛客版,leetcode 5)

1.4 接雨水

1.5 重复数字的所有排列(回溯)

1.6 集合的所有子集 (牛客版,leetcode 78)

2. 树

2.1 判断一颗二叉树是否为二叉搜索树和完全二叉树

2. 2  二叉树的最近公共祖先(leetcode 236)

2.3 二叉搜索树的第k小节点(牛客版)

 2.4 二叉搜索树与双向链表(牛客版)

2.5 重建二叉树(剑指offer,leetcode版)

3. 数组

3.1 数组中的最长连续子序列(牛客版)

3.2 寻找第k大的数(牛客版)

3.3 旋转数组的最小数字

3.4 螺旋数组(牛客版)

4. 链表

4.1 链表中的节点每k个一组翻转(牛客版)

4.2 删除排序链表中的重复元素(牛客版,leetcode 82)

4.3 两个链表相加

4.4 合并k个升序链表(leetcode 23)

4.5 LRU

数学问题

1. 给定一个 0-4随机数生成器 如何生成0-6随机数(leetcode 470)

2. 求平方根


1. 动态规划 / 回溯

动态规划三要素:初始化状态,状态转移方程,边界

对于最长序列系列的问题(公共,上升,回文)的解决方案就是动态规划,采取填表的方式,定义dp[i][j]。

公共对应两个字符串str1和str2,i 和 j 分别对应str1的str2的位置,用于比较。

对于单个字符串dp[i][j],指的是该字符串中第 i 位到第 j 位的运算。

1.1 最长公共子序列(牛客版, leetcode 1143)

题目:给定两个字符串str1和str2,输出连个字符串的最长公共子序列。如过最长公共子序列为空,则输出-1。

输入: "1A2C3D4B56","B1D23CA45B6A"

输出:"123456"

思路:设置二维数组dp[i][j],其中 i 和 j 表示从str1的第 i 位到str2的第 j 位中的最长公共子序列

import java.util.*;

public class Solution {
    /**
     * longest common subsequence
     * @param s1 string字符串 the string
     * @param s2 string字符串 the string
     * @return string字符串
     */
    public String LCS (String s1, String s2) {
        // write code here
        int n1 = s1.length(), n2 = s2.length();
        //默认赋值,[0][?],[?][0]默认两侧皆0,类似公式中0的场景
        int[][] dp = new int[n1 + 1][n2 + 1];
        
        for(int i = 1; i <= n1; i++)
            for(int j = 1; j <= n2; j++){
                if(s1.charAt(i - 1) == s2.charAt(j - 1)){
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }else{
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        
        //反推结果
        int i = n1, j = n2;
        StringBuffer sb = new StringBuffer();
        while(i > 0 && j > 0){
            //反推公式中不相等的场景
            //根据之前的公式,知道两条字符串的下标都前进一位
            if(s1.charAt(i - 1) == s2.charAt(j - 1)){
                sb.append(s1.charAt(i - 1));
                i--;
                j--;
            }else {
                //对应公式中不相等的反推场景
                if(dp[i][j - 1] > dp[i - 1][j]){
                    //找大的那个方向,此处是左边大于上面,则该处的结果是来自左边
                    j--;
                    j--;
                }else if(dp[i][j - 1] < dp[i - 1][j]){
                    i--;
                }else if(dp[i][j - 1] == dp[i - 1][j]){
                    j--;
                }
            }
        }
        
        //由于是从后往前加入字符的,需要反转才能得到正确结果
        return sb.reverse().toString();
    }
}

1.2 最长上升子序列(leetcode 300)

题目:给定数组arr,设长度为n,输出arr的最长上升子序列的长度

输入:[2,1,5,3,6,4,8,9,7]

输出:5

思路:设置并计算dp[i],i 表示从 0 到 i 中当前最长上升数值的个数

class Solution {
    public int lengthOfLIS(int[] nums) {
        if(nums == null || nums.length == 0)
            return 0;
        
        int[] dp = new int[nums.length];
        dp[0] = 1;
        int res = 1;
        for(int i = 1; i < dp.length; i++){
            int maxval = 0;
            for(int j = 0; j < i; j++){
                if(nums[i] > nums[j]){
                    maxval = Math.max(maxval, dp[j]);
                }
            }
            dp[i] = maxval + 1;
            res = Math.max(dp[i], res);
        }

        return res;
    }
}

1.3 最长回文子串(牛客版,leetcode 5)

题目:给定字符串A以及它的长度n,请返回最长回文子串的长度。

输入:"abc1234321ab",12

输出:7

思路:设置二维数组dp[i][j], 表示第 i 个字符到第 j 个字符是否是回文串

import java.util.*;

public class Palindrome {
    public int getLongestPalindrome(String A, int n) {
        // write code here
        if(A == null || n <= 0) return 0;
        
        // 第 i 个字符到第 j 个字符是否是回文串
        boolean[][] dp = new boolean[n][n];
        int maxLen = 0;
        
        // 字符串收尾字母长度差 len = j - i
        for(int len = 0; len < n; len++){
            // 字符串起始位置 i
            for(int i = 0; i + len < n; i++){
                // 字符串终止位置 j
                int j = i + len;
                if(len == 0){
                    dp[i][j] = true;
                }else if(len == 1){
                    dp[i][j] = A.charAt(i) == A.charAt(j);
                }else{
                    dp[i][j] = (A.charAt(i) == A.charAt(j) && dp[i + 1][j - 1]);
                }
                
                if(dp[i][j] && j - i + 1 > maxLen){
                    maxLen = j - i + 1;
                }
            }
        }
        
        return maxLen;
    }
}

1.4 接雨水

对于每一列来说,他能存的雨水量是他 左边最高墙和右边最高墙中较低的那堵墙的高度减去自身墙的高度 。所以可以用数组记录每列左右最高墙的高度,然后计算每一列可以存的雨水量。

class Solution {
    public int trap(int[] height) {
        int sum = 0;
        int[] max_left = new int[height.length];
        int[] max_right = new int[height.length];

        for(int i = 1; i < height.length - 1; i++){
            max_left[i] = Math.max(max_left[i - 1], height[i - 1]);
        }

        for(int i = height.length - 2; i >= 0; i--){
            max_right[i] = Math.max(max_right[i + 1], height[i + 1]);
        }

        for(int i = 1; i < height.length - 1; i++){
            int min = Math.min(max_left[i], max_right[i]);
            if(min > height[i]){
                sum += min - height[i];
            }
        }

        return sum;
    }
}

1.5 重复数字的所有排列(回溯)

题目:给出一组数字,返回该组数字的所有排列

示例:

[1,2,3]的所有排列如下
[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2], [3,2,1].

回溯核心思想:采用递归,在递归调用之前「做选择」,在递归调用之后「撤销选择」

1、路径:已经做出的选择

2、选择列表:当前可以做的选择

3、结束条件:到达决策树底层,无法再做选择的条件

import java.util.ArrayList;
import java.util.Arrays;
public class Solution {
    ArrayList<ArrayList<Integer>> res;
    
    public ArrayList<ArrayList<Integer>> permute(int[] num) {
        res = new ArrayList<ArrayList<Integer>>();
        if(num == null || num.length == 0) return res;
        //对数组元素进行从小到大排序
        Arrays.sort(num);
        ArrayList<Integer> list = new ArrayList<Integer>();
        
        solve(list, num);
        return res;
    }
    
    private void solve(ArrayList<Integer> list, int[] num){
        if(list.size() == num.length){
            res.add(new ArrayList<Integer>(list));
            return;
        }
        for(int i = 0; i < num.length; i++){
            if(!list.contains(num[i])){
                list.add(num[i]);
                solve(list, num);
                list.remove(list.size() - 1);
            }
        }
    }
}

1.6 集合的所有子集 (牛客版,leetcode 78)

 

2. 树

2.1 判断一颗二叉树是否为二叉搜索树和完全二叉树

  • 二叉搜索树:每个节点左边节点小于右边节点,左子树的最大值一定小于根节点,小于右子树的最大值;通过中序遍历,严格递增。
  • 完全二叉树:层序遍历,除了最后的一层,每层都是满的。采用层序遍历,一旦出现null,则队列中剩余的节点必须为叶子节点。
import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 * }
 */

public class Solution {
    /**
     * 
     * @param root TreeNode类 the root
     * @return bool布尔型一维数组
     */
    public boolean[] judgeIt (TreeNode root) {
        // write code here
        // 两个情况分别判断:
        // 二叉搜索树:每个节点左边节点小于右边节点,左子树的最大值一定小于根节点,小于右子树的最大值;通过中序遍历,严格递增
        // 完全二叉树:层序遍历,除了最后的一层,每层都是满的
        if(root == null) return new boolean[]{false, false};
        boolean b1 = isBST(root);
        boolean b2 = isCBT(root);
        return new boolean[]{b1, b2};
    }
    
    private boolean isBST(TreeNode root){
        List<Integer> list = new ArrayList<>();
        midSearch(root, list);
        for(int i = 0; i < list.size() - 1; i++){
            if(list.get(i) > list.get(i + 1))
                return false;
        }
        
        return true;
    }
    
    private void midSearch(TreeNode root, List<Integer> list){
        if(root == null) return;
        midSearch(root.left, list);
        list.add(root.val);
        midSearch(root.right, list);
    }
    
    private boolean isCBT(TreeNode root){
        // 判断一棵树是否为完全二叉树,层序遍历,一旦出现null,则队列中剩余的节点必须为叶子节点
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while(!queue.isEmpty()){
            TreeNode cur = queue.remove();
            if(cur.left == null){
                if(cur.right != null) return false;
                while(!queue.isEmpty()){
                    TreeNode node = queue.remove();
                    if(node.left != null ||node.right != null) return false;
                }
            }else{
                queue.add(cur.left);
            }
            
            if(cur.right == null){
                while(!queue.isEmpty()){
                    TreeNode node = queue.remove();
                    if(node.left != null ||node.right != null) return false;
                }
            }else{
                queue.add(cur.right);
            }
        }
        
        return true;
    }

}

2. 2  二叉树的最近公共祖先(leetcode 236)

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null) return null;
        if(root == p || root == q) return root;
        TreeNode left = lowestCommonAncestor(root.left,p,q);
        TreeNode right = lowestCommonAncestor(root.right,p,q);
        if(left == null) return right;
        if(right == null) return left;
        if(right != null && left != null) return root;
        return null;
    }
}

2.3 二叉搜索树的第k小节点(牛客版)

public class Solution {
    TreeNode res;
    int k;
    TreeNode KthNode(TreeNode pRoot, int k)
    {
        if(pRoot == null || k <= 0) return null;
        this.k = k;
        postOrder(pRoot);
        return res;
    }
    
    private void postOrder(TreeNode pRoot){
        if(pRoot == null) return;
        
        postOrder(pRoot.left);
        if(k == 0) return;
        if(--k == 0) res = pRoot;
        postOrder(pRoot.right);
    }

}

 2.4 二叉搜索树与双向链表(牛客版)

题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

public class Solution
{
    public TreeNode Convert(TreeNode root)
    {
         
        if(root==null)return null;
        if(root.left==null&&root.right==null)return root;
        TreeNode left=Convert(root.left);
        TreeNode p=left;
        while(p!=null&&p.right!=null)
        {
            p=p.right;
        }
        if(left!=null)
        {
         p.right=root;
          root.left=p;
        }
       TreeNode right=Convert(root.right);
        if(right!=null)
         {
            root.right=right;
            right.left=root;
        }
         
      return  left!=null?left:root; 
    }
}

2.5 重建二叉树(剑指offer,leetcode版)

题目:输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if (preorder == null || preorder.length == 0) {
            return null;
        }
        Map<Integer, Integer> indexMap = new HashMap<Integer, Integer>();
        int length = preorder.length;
        for (int i = 0; i < length; i++) {
            indexMap.put(inorder[i], i);
        }
        TreeNode root = buildTree(preorder, 0, length - 1, inorder, 0, length - 1, indexMap);
        return root;
    }

    public TreeNode buildTree(int[] preorder, int preorderStart, int preorderEnd, int[] inorder, int inorderStart, int inorderEnd, Map<Integer, Integer> indexMap) {
        if (preorderStart > preorderEnd) {
            return null;
        }
        int rootVal = preorder[preorderStart];
        TreeNode root = new TreeNode(rootVal);
        if (preorderStart == preorderEnd) {
            return root;
        } else {
            int rootIndex = indexMap.get(rootVal);
            int leftNodes = rootIndex - inorderStart, rightNodes = inorderEnd - rootIndex;
            TreeNode leftSubtree = buildTree(preorder, preorderStart + 1, preorderStart + leftNodes, inorder, inorderStart, rootIndex - 1, indexMap);
            TreeNode rightSubtree = buildTree(preorder, preorderEnd - rightNodes + 1, preorderEnd, inorder, rootIndex + 1, inorderEnd, indexMap);
            root.left = leftSubtree;
            root.right = rightSubtree;
            return root;
        }
    }
}

3. 数组

3.1 数组中的最长连续子序列(牛客版)

题:给定无序数组arr,返回其中最长的连续序列的长度(要求值连续,位置可以不连续,例如 3,4,5,6为连续的自然数)

例:输入:[100,4,200,1,3,2]     输出:4

  • 方法一:排序,然后再遍历一遍找最长连续递增数列,时间复杂度O(NlogN)
  • 方法二:使用HashMap或者HashSet,将数组元素存入set中,然后遍历set,先找到每个序列的开头元素
import java.util.*;

public class Solution {
    public int MLS (int[] arr) {
        // write code here
        if(arr == null || arr.length == 0) return 0;
        HashSet<Integer> set = new HashSet<>();
        int maxLen = 0;
        
        for(int value : arr){
            set.add(value);
        }
        
        for(int num : set){
            if(!set.contains(num - 1)){
                int currentNum = num;
                int currentLen = 1;
                while(set.contains(currentNum + 1)){
                    currentNum += 1;
                    currentLen++;
                }
                
                maxLen = Math.max(maxLen, currentLen);
            }
        }
        
        return maxLen;
    }
}

3.2 寻找第k大的数(牛客版)

给定一个整数数组a,同时给定它的大小n和要找的K(K在1到n之间),请返回第K大的数

输入:[1,3,5,2,2],5,3

输出:2

思路:快速排序 + 递归(注意第 k 大是从后往前数,第 k 小是从小往大)

import java.util.*;

public class Finder {
    public int findKth(int[] a, int n, int K) {
        // write code here
        return findK(a, 0, n - 1, K);
    }
    
    private int findK(int[] arr, int left, int right, int k){
        if(left <= right){
            int temp = quickSort(arr, left, right);
            
            if(temp == arr.length - k){
                return arr[temp];
            }else if(temp > arr.length - k){
                return findK(arr, left, temp - 1, k);
            }else{
                return findK(arr, temp + 1, right, k);
            }
        }

        return -1;
    }
    
    private int quickSort(int[] a, int left, int right){
        int key = a[left];
        while(left < right){
            while(left < right && a[right] >= key){
                right--;
            }
            
            a[left] = a[right];
            
            while(left < right && a[left] <= key){
                left++;
            }
            
            a[right] = a[left];
        }
        
        a[left] = key;
        
        return left;
    }
}

3.3 旋转数组的最小数字

题目:输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。

例子:数组[3,4,5,1,2]为[1,2,3,4,5]的一个旋转,该数组的最小值为1。建议使用O(logn)时间复杂度

思想:二分查找的变种,注意旋转后的边界

import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        if(array.length == 0 || array == null)
            return 0;
        
        int left = 0;
        int right = array.length - 1;
        int mid = left;
        
        while(array[left] >= array[right]){
            // 二分查找的边界
            if(right - left == 1){
                mid = right;
                break;
            }
            
            mid = (left + right) / 2;
            if(array[mid] >= array[left])
                left = mid;
            else if(array[mid] <= array[right])
                right = mid;
        }
        
        return array[mid];
    }
}

3.4 螺旋数组(牛客版)

题目:给定一个m x n大小的矩阵(m行,n列),按螺旋的顺序返回矩阵中的所有元素。

例如:

[
    [ 1, 2, 3 ],
    [ 4, 5, 6 ],
    [ 7, 8, 9 ]
]

返回:[1,2,3,6,9,8,7,4,5]

import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> spiralOrder(int[][] matrix) {
        ArrayList<Integer> res = new ArrayList<Integer>();
        
        if(matrix.length == 0) return res;
        
        int rowBegin = 0;
        int rowEnd = matrix.length - 1;
        int colBegin = 0;
        int colEnd = matrix[0].length - 1;
        
        while(rowBegin <= rowEnd && colBegin <= colEnd){
            for(int j = colBegin; j <= colEnd; j++){
                res.add(matrix[rowBegin][j]);
            }
            
            rowBegin++;
            for(int i = rowBegin; i <= rowEnd; i++){
                res.add(matrix[i][colEnd]);
            }
            
            colEnd--;
            
            if(rowBegin <= rowEnd){
                for(int j = colEnd; j >= colBegin; j--){
                    res.add(matrix[rowEnd][j]);
                }
            }
            
            rowEnd--;
            
            if(colBegin <= colEnd){
                for(int i = rowEnd; i >= rowBegin; i--){
                    res.add(matrix[i][colBegin]);
                }
            }
            colBegin++;
        }
        return res;
    }
}

3.5 字符串最长无重复子串(牛客版,leetcode 48)

题目:给定一个数组arr,返回arr的最长无的重复子串的长度(无重复指的是所有数字都不相同)。

解法:使用hashmap来保存重复字符的位置。

import java.util.*;


public class Solution {
    public int maxLength (int[] arr) {
        // write code here
        HashMap<Integer, Integer> map = new HashMap<>();
        int max = 1;
        for(int start = 0, end = 0; end < arr.length; end++){
            if(map.containsKey(arr[end])){
                start = Math.max(start, map.get(arr[end]) + 1);
            }
            max = Math.max(max, end - start + 1);
            map.put(arr[end], end);
        }
        
        return max;
    }
}

4. 链表

4.1 链表中的节点每k个一组翻转(牛客版)

public class Solution {
    /**
     * 
     * @param head ListNode类 
     * @param k int整型 
     * @return ListNode类
     */
    public ListNode reverseKGroup (ListNode head, int k) {
        // write code here
        
        if(head == null || head.next == null || k < 2)
            return head;
        
        ListNode res = new ListNode(-1);
        res.next = head;
        ListNode pre = res;
        ListNode end = res;
        
        while(end != null){
            for(int i = 0; i < k && end != null; i++){
                end = end.next;
            }
            
            if(end == null) break;
            
            ListNode start = pre.next;
            ListNode next = end.next;
            end.next = null;
            pre.next = reverseList(start);
            start.next = next;
            pre = start;
            end = pre;
        }
        
        return res.next;
    }
    
    private ListNode reverseList(ListNode head){
        ListNode preNode = null, pNode = head;
        while(pNode != null){
            ListNode pNext = pNode.next;
            pNode.next = preNode;
            preNode = pNode;
            pNode = pNext;
        }
        
        return preNode;
    }
}

4.2 删除排序链表中的重复元素(牛客版,leetcode 82)

题目:给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。

给出的链表为1→2→3→3→4→4→5, 返回 1→2→5.
给出的链表为1→1→1→2→3, 返回 2→3.

import java.util.*;

public class Solution {
    public ListNode deleteDuplicates (ListNode head) {
        // write code here
        if(head == null || head.next == null)
            return head;
        
        ListNode res = new ListNode(-1);
        res.next = head;
        ListNode preNode = res;
        ListNode pNode = head;
        
        while(pNode != null && pNode.next != null){
            if(preNode.next.val != pNode.next.val){
                preNode = preNode.next;
                pNode = pNode.next;
            }else{
                while(pNode != null && pNode.next != null && preNode.next.val == pNode.next.val){
                    pNode = pNode.next;
                }
                
                preNode.next = pNode.next;
                pNode = pNode.next;
            }
        }
        
        return res.next;
        
    }
}

4.3 两个链表相加

给定两个这种链表,请生成代表两个整数相加值的结果链表。

例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。

思路:先反转,再相加,注意进位以及最后一次相加(String类型的大数加法思路一致)

import java.util.*;


public class Solution {
    public ListNode addInList (ListNode head1, ListNode head2) {
        // write code here
        if(head1 == null) return head2;
        if(head2 == null) return head1;
        
        ListNode l1 = reverseList(head1);
        ListNode l2 = reverseList(head2);
        int carry = 0;
        ListNode res = new ListNode(-1);
        ListNode curNode = res;
        
        while(l1 != null || l2 != null){
            int num1 = l1 == null ? 0 : l1.val;
            int num2 = l2 == null ? 0 : l2.val;
            
            int val = (num1 + num2 + carry) % 10;
            carry = (num1 + num2 + carry) / 10;
            
            curNode.next = new ListNode(val);
            if(l1 != null) 
                l1 = l1.next;
            if(l2 != null)
                l2 = l2.next;
            
            curNode = curNode.next;
        }
        
        return reverseList(res.next);
    }
    
    public ListNode reverseList(ListNode head){
        ListNode preNode = null;
        ListNode curNode = head;
        
        while(curNode != null){
            ListNode nextNode = curNode.next;
            curNode.next = preNode;
            preNode = curNode;
            curNode = nextNode;
        }
        
        return preNode;
    }
}

4.4 合并k个升序链表(leetcode 23)

题目:合并 k 个已排序的链表并将其作为一个已排序的链表返回。

思路:归并排序法 + 两个链表合并法

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if(lists == null || lists.length == 0) return null;

        return merge(lists, 0, lists.length - 1);
    }

    private ListNode merge(ListNode[] lists, int left, int right){
        if(left == right) return lists[left];

        int mid = left + (right - left) / 2;
        ListNode l1 = merge(lists, left, mid);
        ListNode l2 = merge(lists, mid + 1, right);
        return mergeTwoLists(l1, l2);
    }

    private ListNode mergeTwoLists(ListNode l1, ListNode l2){
        ListNode res = new ListNode(-1);
        ListNode pNode = res;

        while(l1 != null && l2 != null){
            if(l1.val <= l2.val){
                pNode.next = l1;
                l1 = l1.next;
            }else{
                pNode.next = l2;
                l2 = l2.next;
            }
            pNode = pNode.next;
        }

        pNode.next = l1 == null ? l2 : l1;
        return res.next;
    }
}

4.5 LRU

class LRUCache {
    class Node {
        public int key, val;
        public Node prev, next;
        public Node(int key, int val){
            this.key = key;
            this.val = val;
        }
    }

    class DoubleList{
        private Node head, tail;
        private int size;

        public DoubleList(){
            head = new Node(0, 0);
            tail = new Node(0, 0);
            head.next = tail;
            tail.prev = head;
            size = 0;
        }

        public void addFirst(Node x){
            x.next = head.next;
            x.prev = head;
            head.next.prev = x;
            head.next = x;
            size++;
        }

        public void remove(Node x){
            x.prev.next = x.next;
            x.next.prev = x.prev;
            size--;
        }

        public Node removeLast(){
            if(tail.prev == head){
                return null;
            }
            Node last = tail.prev;
            remove(last);
            return last;
        }

        public int size(){
            return this.size;
        }

    }

    public HashMap<Integer, Node> map;
    private DoubleList cache;
    private int cap;
    
    public LRUCache(int capacity) {
        map = new HashMap<>();
        cache = new DoubleList();
        this.cap = capacity;
    }
    
    public int get(int key) {
        if(!map.containsKey(key)){
            return -1;
        }

        int val = map.get(key).val;
        put(key, val);

        return val;
    }
    
    public void put(int key, int value) {
        Node x = new Node(key, value);

        if(map.containsKey(key)){
            cache.remove(map.get(key));
            cache.addFirst(x);
            map.put(key, x);
        }else{
            if(cache.size == cap){
                Node last = cache.removeLast();
                map.remove(last.key);
            }

            cache.addFirst(x);
            map.put(key, x);
        }
    }
}

 

数学问题

1. 给定一个 0-4随机数生成器 如何生成0-6随机数(leetcode 470)

定理:已知 rand_N() 可以等概率的生成[1, N]范围的随机数。那么:

(rand_X() - 1) × Y + rand_Y() ==> 可以等概率的生成[1, X * Y]范围的随机数,即实现了 rand_XY()

例:(rand9() - 1) × 7 + rand7() = rand63();

class Solution extends SolBase {
    public int rand10() {
        while(true) {
            int a = rand7();
            int b = rand7();
            int num = (a-1)*7 + b; // rand 49
            if(num <= 40) return num % 10 + 1; // 拒绝采样
            
            a = num - 40; // rand 9
            b = rand7();
            num = (a-1)*7 + b; // rand 63
            if(num <= 60) return num % 10 + 1;
            
            a = num - 60; // rand 3
            b = rand7();
            num = (a-1)*7 + b; // rand 21
            if(num <= 20) return num % 10 + 1;
        }
    }
}

2. 求平方根

 

  • 8
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值