字节面试高频百题(三)

继续分享面试经常出现的算法题和解法。

第一部分见:字节面试高频百题(一)

第二部分见:字节面试高频百题(二)

41、判断回文

牛客 141 判断是否为回文字符串:

思路:

  • 前后指针相向而行
go 复制代码
public boolean judge (String s) {
        // 双指针算法,判断回文串
        // 一左一右两个指针相向而行
        int left = 0, right = s.length() - 1;
        while (left < right) {
            if (s.charAt(left) != s.charAt(right)) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }

42、单链表的排序

牛客70 单链表的排序:

思路:

  • 快慢指针找中点,拆成两个链表,合并
go 复制代码
//返回两个排好序且合并好的子链表
    public ListNode sortInList (ListNode head) {

        //终止条件:链表为空或者只有一个元素,直接就是有序的
        if (head == null || head.next == null) return head;

        ListNode left = head;
        ListNode mid = head.next;
        ListNode right = head.next.next;
        //本级任务:找到这个链表的中间节点,从前面断开,分为左右两个子链表,进入子问题排序
        //右边的指针到达末尾时,中间的指针指向该段链表中间
        while (right != null && right.next != null) {
            left = left.next;
            mid = mid.next;
            right = right.next.next;
        }
        //左边指针指向左端的最右一个节点,从这里断开
        left.next = null;
        
        //拆解左右链表分别排序
        ListNode leftHead = sortInList(head);
        ListNode rightHead = sortInList(mid);
        //合并两个升序链表
        return mergeTwoLists(leftHead, rightHead );
    }

    //合并两个有序链表的函数
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {

        // 虚拟头节点
        ListNode dummy = new ListNode(-1), p = dummy;
        ListNode p1 = list1, p2 = list2;

        while (p1 != null && p2 != null) {
            // 比较 p1 和 p2 两个指针,将值较小的节点接到 p 指针
            if (p1.val > p2.val) {

                p.next = p2;
                p2 = p2.next;
            } else {

                p.next = p1;
                p1 = p1.next;
            }

            // p 指针不断前进
            p = p.next;

        }

        // p2 走完,把 p1 剩下的节点接到 p 上
        if (p1 != null) {
            p.next = p1;
        }

        // p1 走完,把 p2 剩下的节点接到 p 上
        if (p2 != null) {
            p.next = p2;
        }

        // 返回去掉虚拟头节点的链表
        return dummy.next;

    }

43、数组中出现次数超过一半的数字

牛客 73 数组中出现次数超过一半的数字:

思路:

  • 排序取中位数

  • 哈希表存数值到个数的映射

  • 投票法。假设某个数是众数,则票数+1,遇到非嫌疑众数的数,票数-1,当票数为0则说明当前数不是众数

go 复制代码
public int MoreThanHalfNum_Solution (int[] numbers) {
        Arrays.sort(numbers);
        return numbers[numbers.length / 2];
    }
go 复制代码
HashMap<Integer,Integer> num2Cnt = new HashMap<>();

    public int MoreThanHalfNum_Solution (int[] numbers) {

        int half = numbers.length / 2;
        
        for(int i = 0;i < numbers.length ;i++){

            int curNumCnt = num2Cnt.getOrDefault(numbers[i],0);
            
            num2Cnt.put(numbers[i],curNumCnt+1);

            if(curNumCnt + 1 > half) return numbers[i];
        }

        return -1;
    }
go 复制代码
public int MoreThanHalfNum_Solution (int[] numbers) {

        //初始化候选人为第一个元素,候选人的投票次数为1
        int cond =numbers[0] , cnt = 1;
        for (int i = 1; i < numbers.length; i++) {
            //如果当前数=cond,则cnt++,否则cnt--
            if (cond == numbers[i]) cnt++;
            else cnt--;

            //cnt为0,选择下一个元素为候选元素,并且置count=1
            if (cnt == 0) {
                cond = numbers[i+1];
                //更新投票次数
                cnt = 1;
            } 
        }
        return cond;
    }

44、平衡二叉树

力扣110/牛客 62 判断是否为平衡二叉树:

思路:

  • dfs,判断左子树为平衡树,判断右子树为平衡树,左子树深度和右子树深度差距小于等于1为平衡树

O(n)解法:

go 复制代码
public boolean IsBalanced_Solution (TreeNode root) {

        if (root == null)return true;

        //深度差
        return getDepthDiff(root) != -1;
    }

    //返回root为根节点对应的树的左右子树的深度差
    public int getDepthDiff(TreeNode root) {

        if (root == null) return 0;

        //递归计算当前root左子树的深度差
        int left = getDepthDiff(root.left);
        //当前节点左子树不平衡,则该树不平衡,-1表达深度大于1的场景
        if (left < 0) return -1;

        int right = getDepthDiff(root.right);
        if (right < 0) return -1;

        //计算深度差:大于1认为是 -1,否则取最大+1(把根节点弄进来)
        return Math.abs(left - right) > 1 ? -1 : Math.max(left, right) + 1;
    }

O(n2)解法:

go 复制代码
public boolean isBalanced(TreeNode root) {

        if (root == null)
            return true;

        if (!isBalanced(root.left) || !isBalanced(root.right))
            return false;

        return Math.abs(depth(root.left) - depth(root.right)) <= 1;
    }

    // 返回root为根节点对应的树的高度
    public int depth(TreeNode root) {

        if (root == null)
            return 0;
        return Math.max(depth(root.left), depth(root.right)) + 1;
    }

45、矩阵的最小路径和

力扣 64/牛客 59 矩阵最小路径和:

思路:

  • 动态规划:dp[i][j] = dp[i][j] + Min(matrix[i][j-1],matrix[i-1][j])

  • dfs,要求空间复杂度为O(n),则说明不能再新建 dp 矩阵,直接使用matrix

go 复制代码
public int minPathSum (int[][] matrix) {

        int m = matrix.length, n = matrix[0].length;
        dp[i][j] = dp[i][j] + Min(matrix[i][j-1],matrix[i-1][j])
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (i == 0 && j == 0) continue;

                if (i == 0 ) {
                    matrix[i][j] = matrix[i][j] + matrix[i][j - 1];
                } else if (j == 0) {
                    matrix[i][j] = matrix[i][j] + matrix[i - 1][j];
                } else {
                    matrix[i][j] =  matrix[i][j] + Math.min(matrix[i][j - 1], matrix[i - 1][j]);
                }
            }
        }
        return matrix[m - 1][n - 1];

    }

46、表达式求值

牛客 137 表达式求值:

思路:

  • 栈+递归
go 复制代码
public int solve (String s) {
        ArrayList<Integer> res = function(s, 0);
        return res.get(0);
    }

    public ArrayList<Integer> function(String s, int index) {
        
        Stack<Integer> stack = new Stack<Integer>();
        int num = 0;
        char op = '+';
        int i;
        for (i = index; i < s.length(); i++) {
            //数字转换成int数字
            //判断是否为数字
            if (s.charAt(i) >= '0' && s.charAt(i) <= '9') {
                num = num * 10 + s.charAt(i) - '0';
                if (i != s.length() - 1)
                    continue;
            }
            //碰到'('时,把整个括号内的当成一个数字处理
            if (s.charAt(i) == '(') {
                //递归处理括号
                ArrayList<Integer> res = function(s, i + 1);
                num = res.get(0);
                i = res.get(1);
                if (i != s.length() - 1)
                    continue;
            }
            switch (op) {
                //加减号先入栈
                case '+':
                    stack.push(num);
                    break;
                case '-':
                    //相反数
                    stack.push(-num);
                    break;
                //优先计算乘号
                case '*':
                    int temp = stack.pop();
                    stack.push(temp * num);
                    break;
            }
            num = 0;
            //右括号结束递归
            if (s.charAt(i) == ')')
                break;
            else
                op = s.charAt(i);
        }
        int sum = 0;
        //栈中元素相加
        while (!stack.isEmpty())
            sum += stack.pop();
        ArrayList<Integer> temp = new ArrayList<Integer>();
        temp.add(sum);
        temp.add(i);
        return temp;
    }

47、逆波兰表达式求值

牛客 216 逆波兰表达式求值:

思路:

  • 栈。遇到数字入栈,遇见符号弹出两个数字做运算,然后将结果入栈
go 复制代码
public int evalRPN (String[] tokens) {
        Stack<Integer> stack = new Stack<>();
        for (int i = 0 ; i < tokens.length; ++i) {
            if (isOperator(tokens[i])) {
                Integer num1 = stack.pop();
                Integer num2 = stack.pop();
                Integer res = operator(num2, num1, tokens[i]);
                stack.push(res);
            } else {
                stack.push(Integer.parseInt(tokens[i]));
            }
        }
        return stack.pop();
    }

    static int operator(int n1, int n2, String op) {
        if (op.equals("+")) return n1 + n2;
        else if (op.equals("-")) return n1 - n2;
        else if (op.equals("*")) return n1 * n2;
        else if (op.equals("/")) return n1 / n2;
        else return -1;
    }

    static boolean isOperator(String op) {
        return op.equals("+") || op.equals("-") || op.equals("*") || op.equals("/");
    }

48、最小的K个数

牛客 119 最小的K个数:

思路:

  • topk 问题求最小,建大顶堆

自建大顶堆的代码:

go 复制代码
public ArrayList<Integer> GetLeastNumbers_Solution (int[] input, int k) {

        ArrayList<Integer> res = new ArrayList<>();

        if (input.length == 0 || k == 0) return res;
        
        //topk 求最小,建大顶堆
        pq = new int[k + 1];
        //构建前k个元素组成的大顶堆
        for (int i = 0; i < k; i++) {
            insert(input[i]);
        }

        //从第k+1个开始依次比较堆顶元素,比堆顶元素小则替换
        for (int i = k; i < input.length; i++) {
            int maxVal = pq[1];
            if (input[i] < maxVal) {
                pq[1] = input[i];
                //让pq[1]下沉到正确位置
                sink(1);

            }
        }


        for (int i = 1; i <= k; i++) {
            res.add(pq[i]);
        }
        return res;
    }

    //存储元素的数组
    private int[] pq;

    // 当前元素个数
    private int size = 0;

    //下沉第 x 个元素,以维护最大堆性质
    private void sink(int x) {
        // 如果沉到堆底,就沉不下去了
        while (left(x) <= size) {
            // 先假设左边节点较大
            int max = left(x);
            // 如果右边节点存在,比一下大小
            if (right(x) <= size && less(max, right(x)))
                max = right(x);
            // 结点 x 比俩孩子都大,就不必下沉了
            if (less(max, x)) break;
            // 否则,不符合最大堆的结构,下沉 x 结点
            swap(x, max);
            x = max;
        }
    }

    private int parent(int root) {
        return root / 2;
    }

    private int left(int root) {
        return root * 2;
    }
    private int right(int root) {
        return root * 2 + 1;
    }

    //插入函数
    private void insert(int val) {
        size++;
        //把新元素加到最后
        pq[size] = val;
        //让它上浮到正确的位置
        swim((size));

    }

    //上浮第 x 个元素,以维护最大堆性质
    private void swim(int x) {
        //如果浮到堆顶,就不能再上浮
        while (x > 1 && less(parent(x), x)) {
            //如果第x个元素比上层大
            //将x换上去
            swap(parent(x), x);
            x = parent(x);
        }
    }

    //pq[i]是否比pq[j]小
    private boolean less(int i, int j) {
        return pq[i] - pq[j] < 0;
    }

    //交换数组的两个元素
    private void swap(int i, int j) {
        int temp = pq[i];
        pq[i] = pq[j];
        pq[j] = temp;
    }

使用JDK优先级队列的代码:

go 复制代码
public ArrayList<Integer> GetLeastNumbers_Solution (int[] input, int k) {

        ArrayList<Integer> res = new ArrayList<>();

        if (input.length == 0 || k == 0) return res;
        
        //topk 求最小,建大顶堆
        PriorityQueue<Integer> pq = new PriorityQueue<>(k,(a,b)->(b-a));
        
        //构建前k个元素组成的大顶堆
        for (int i = 0; i < k; i++) {
            pq.offer(input[i]);
        }

        //从第k+1个开始依次比较堆顶元素,比堆顶元素小则替换
        for (int i = k; i < input.length; i++) {
            int maxVal = pq.peek();
            if (input[i] < maxVal) {
                pq.poll();
                pq.offer(input[i]);

            }
        }

        while(!pq.isEmpty()){
            res.add(pq.poll());
        }
        return res;
    }

49、字符串出现次数的TopK问题

牛客97 字符串出现次数的TopK问题:

思路:

  • 最大堆实现的优先级队列
go 复制代码
public  String[][] topKstrings (String[] strings, int k) {
        // write code here

        PriorityQueue<MyNode> queue = new PriorityQueue<>(new MyComparator());

        HashMap<String, Integer> map = new HashMap<>();
        for (int i = 0; i < strings.length; i++) {
            map.put(strings[i], map.getOrDefault(strings[i], 0) + 1);
        }

        //入堆
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            queue.add(new MyNode(entry.getKey(), entry.getValue()));
        }

        String[][] result = new String[k][2];
        int j = 0;
        while (j < k && !queue.isEmpty()) {
            MyNode node = queue.poll();
            result[j][0] = node.val;
            result[j++][1] = String.valueOf(node.num);
        }
        return result;

    }

    class MyNode {
        String val;
        int num;
        MyNode(String val, int num) {
            this.num = num;
            this.val = val;
        }
    }
    
    class MyComparator implements Comparator<MyNode> {

        @Override
        public int compare(MyNode o1, MyNode o2) {
            if (o1.num == o2.num) {
                //字典序小的在前 所以 o1 比 o2
                return o1.val.compareTo(o2.val);
            } else {
                //数量大的在前所以 o2 - o1
                return o2.num - o1.num;
            }

        }
    }

50、进制转换

牛客 112 进制转换:

思路:

  • 除N取余,然后倒序排列,高位补零。
go 复制代码
public String solve (int M, int N) {
        if (M == 0)  return "0";
        String s = "0123456789ABCDEF";
        StringBuffer sb = new StringBuffer();
        boolean f = false;
        if (M < 0) {
            f = true;
            M = -M;
        }
        while (M != 0) {
            sb.append(s.charAt(M % N));
            M /= N;
        }
        if (f) sb.append("-");
        return sb.reverse().toString();
    }

51、判断一个链表是否为回文结构

牛客 96 判断一个链表是否为回文结构

思路:

  • 找到中间节点,反转后半部分,两部分从头等值比对
go 复制代码
public boolean isPail (ListNode head) {
        //快慢指针找到中点
        ListNode fast = head, slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        //fast != null 说明是奇数长度
        if (fast != null) slow = slow = slow.next;
        
        slow = reverseList(slow);
        fast = head;
        while (slow != null && fast != null) {
            if (slow.val != fast.val) return false;
            fast = fast.next;
            slow = slow.next;
        }

        return true;
    }

    public ListNode reverseList(ListNode head) {

        if (head == null || head.next == null) return head;

        ListNode last = reverseList(head.next);
        head.next.next = head;
        head.next = null;

        return last;

    }

52、二叉树中和为某一值的路径(是否存在)

牛客 9 二叉树中和为某一值的路径(一):

思路:

  • 前序遍历,每走过一个节点更新 sum 值,sum 为0 且是叶子节点更新路径和标识,并退出
go 复制代码
//路径和等于sum的存在标识
    private boolean has = false;

    public boolean hasPathSum (TreeNode root, int sum) {
        //遍历二叉树,走过每个节点更新sum值,sum为0且是叶子节点更新路径和标识,并退出
        traverse(root, sum);
        return has;
    }

    private void traverse(TreeNode root, int sum) {

        if (root == null) return;
        sum = sum - root.val;
        //sum为0并且当前节点是叶子节点
        if (sum == 0 && root.left == null && root.right == null) {
            has = true;
            return;
        }
        traverse(root.left, sum);
        traverse(root.right, sum);
    }

53、二叉树中和为某一值的路径(所有路径)

牛客 8 二叉树中和为某一值的路径(二)::

思路:

  • 回溯的思路,在(一)的遍历基础上增加路径更新、结果追加、撤销选择的逻辑。
go 复制代码
ArrayList<ArrayList<Integer>> res = new ArrayList<>();

    LinkedList<Integer> path = new LinkedList<>();

    public ArrayList<ArrayList<Integer>> FindPath (TreeNode root, int sum) {

        traverse(root, sum);
        return res;
    }

    private void traverse(TreeNode root, int sum) {

        if (root == null) return;
        //路径更新
        path.add(root.val);

        sum = sum - root.val;

        //sum为0并且当前节点是叶子节点
        if (sum == 0 && root.left == null && root.right == null) {
            //找到一条路径
            res.add(new ArrayList(path));
        }
        traverse(root.left, sum);
        traverse(root.right, sum);

        //撤销选择
        path.removeLast();
    }

54、二叉树中和为某一值的路径(所有子路径)

牛客 162 二叉树中和为某一值的路径(三):

思路:

  • 在(二)的基础上,再次进行树的遍历统计路径数

  • 注意:路径不再要求叶子节点结束

go 复制代码
private int res = 0;
    public int FindPath (TreeNode root, int sum) {
        if (root == null) return res;

        //查询根节点的路径数
        traverse(root,sum);

        //查询子节点的路径数
        FindPath(root.left,sum);
        FindPath(root.right,sum);
        return res;
    }

    //查询以某节点为根的路径数
    private void traverse(TreeNode root, int sum) {

        if (root == null) return;
        sum = sum - root.val;
        //sum为0【注意此处不再要求叶子节点结束,要去掉叶子节点判断】
        if (sum == 0) {
            res++;
        }
        traverse(root.left, sum);
        traverse(root.right, sum);
    }

55、链表内指定区间反转

力扣 92 反转链表2:

牛客21 链表内指定区间反转:

go 复制代码
public ListNode reverseBetween(ListNode head, int left, int right) {
        // base case
        if (left == 1)
            return reverseN(head, right);

        // 前进到反转的起点触发 base casee
        head.next = reverseBetween(head.next, left - 1, right - 1);

        return head;
    }

    // 后驱节点
    ListNode successor = null;

    // 反转以 head 为起点的 n 个节点,返回新的头节点
    ListNode reverseN(ListNode head, int n) {
        if (n == 1) {
            // 记录第 n+1 个节点
            successor = head.next;
            return head;
        }
        // 以 head.next 为起点,需要反转前 n-1 个节点
        ListNode last = reverseN(head.next, n - 1);

        // head.next为反转后的表尾,表尾追加head
        head.next.next = head;

        // 让反转之后的 head 节点和后面的节点连起来
        head.next = successor;

        return last;

    }

56、不同路径的数目

力扣 63/牛客 34 不同路径的数目:

思路:

  • dp 迭代 or 递归
go 复制代码
public int uniquePaths (int m, int n) {

        //dp[i][j]代表 [0][0]到[i][j]的路径数
        int[][]  dp = new int[m][n];

        for(int i = 0;i < m;i++){
            for(int j = 0;j <n;j++){

                if(i == 0 || j == 0) {
                    dp[i][j] = 1;
                    continue;
                }
                
                dp[i][j] = dp[i][j-1] + dp[i-1][j];
            }
        }

        return dp[m-1][n-1];
    }
go 复制代码
public int uniquePaths (int m, int n) {

        if (m == 1 || n == 1) return 1;

        return uniquePaths(m - 1, n) + uniquePaths(m, n - 1);
    }

57、合并区间

力扣 56/牛客 37 合并区间:

思路:

  • 对于几个相交区间合并后的结果区间 x,x.start 一定是这些相交区间中 start 最小的,x.end 一定是这些相交区间中 end 最大的

  • 对 start 排序

go 复制代码
/*
     * public class Interval {
     *   int start;
     *   int end;
     *   public Interval(int start, int end) {
     *     this.start = start;
     *     this.end = end;
     *   }
     * }
     */
 //对于几个相交区间合并后的结果区间 x,x.start 一定是这些相交区间中 start 最小的,x.end 一定是这些相交区间中 end 最大的
    public ArrayList<Interval> merge (ArrayList<Interval> intervals) {

        LinkedList<Interval> res = new LinkedList<>();

        if(intervals.isEmpty()) return new ArrayList(res);

        intervals.sort((a,b)->(a.start-b.start));

        Interval firstInterval = intervals.get(0);
        res.add(firstInterval);

        for(int i = 1; i < intervals.size();i++){

            Interval curr = intervals.get(i);
            //res 中最后一个元素的引用
            Interval last = res.getLast();
            if(curr.start <= last.end){
                last.end = Math.max(last.end,curr.end);
            }else{
                //处理下一个待合并区间
                res.add(curr);
            }
        }
        return new ArrayList(res);
    }

58、排序数组中找到上中位数

牛客 36 在两个长度相等的排序数组中找到上中位数:

思路:

  • 双指针
go 复制代码
public int findMedianinTwoSortedAray (int[] arr1, int[] arr2) {

        int len = arr1.length + arr2.length;
        int mid = 0;
        //求出合并后中位数的下标
        if (len % 2 == 0) mid = len / 2;
        else mid = len / 2 + 1;

        int index1= 0,index2 = 0;
        int res = 0;
        for(int i = 0;i < mid;i++){
            if(arr1[index1] < arr2[index2]){
                res = arr1[index1];
                index1++;
            }else{
                res = arr2[index2];
                index2++;
            }
        }
        return res;
    }

59、搜索二叉树和完全二叉树

牛客 60 判断一棵二叉树是否为搜索二叉树和完全二叉树

思路:

  • 搜索二叉树,明确定义是 root为左子树的最大值,右子树的最小值,遍历参数引入双节点

  • 完全二叉树,每一层不存在空节点。层序遍历,null值也入队。遍历遇到空节点,检查队列是否还有非空节点,存在说明二叉树不完全。

go 复制代码
public boolean[] judgeIt (TreeNode root) {

        boolean isBst = traverse(root, null, null);
        return new boolean[] {isBst, isAllTree(root)};
    }

    public boolean traverse(TreeNode root, TreeNode min, TreeNode max) {

        if (root == null) return true;
        if (min != null && min.val > root.val) return false;
        if (max != null && max.val < root.val) return false;

        //root 为左子树的最大值
        boolean leftIsBst =  traverse(root.left, min, root);
        //root 为右子树的最小值
        boolean rightIsBst =  traverse(root.right, root, max);
        return leftIsBst && rightIsBst;
    }

    public boolean isAllTree(TreeNode root) {
        
        if (root == null) return true;

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {

                 //遍历到的节点出队
                TreeNode node = queue.poll();
                if(node != null){
                    //【此处不判空】子节点是空值也入队
                    queue.offer(node.left);
                    queue.offer(node.right);
                }else{
                    //遇到空节点,检查队列是否还有非空节点,存在说明二叉树不完全
                    while (!queue.isEmpty()) {
                        if(queue.poll() != null) return false;
                    }
                }
        }
        return true;
    }

60、删除有序链表中重复的元素-II

牛客 24 删除有序链表中重复的元素-II

思路:

  • 双指针,隔一齐头并进,出现重复则只前进快指针,直到不相等的时候执行删除操作
go 复制代码
public ListNode deleteDuplicates (ListNode head) {
        if (head == null) return null;

        ListNode dummy = new ListNode(-1);
        dummy.next = head;

        ListNode slow = head, fast = head.next;
        ListNode pre = dummy;

        while (fast != null) {
            //两值不等,齐头并进
            if (slow.val != fast.val) {

                //如果距离相差1,更新前驱指针,继续向前
                if (slow.next == fast) {
                    pre = slow;
                    slow = slow.next;
                    fast = fast.next;
                }else{
                    //执行删除操作 fast 此时在最后一个删除节点后,slow此时是待删除的第一个节点
                    pre.next = fast;
                    slow = pre;

                }

            } else if (slow.val == fast.val) {
                //处理结尾重复
                if(fast.next == null){
                    pre.next = null;
                }

                //值相等后,slow不动,fast继续走
                fast = fast.next;
            }
        }
        return dummy.next;
    }

我是蜗牛,大厂程序员,专注技术原创和个人成长,正在互联网上摸爬滚打。欢迎关注我,和蜗牛一起成长,我们一起牛~下期见!

推荐阅读:

字节面试高频百题(二)

《Java 工程师成神之路》.pdf

点阅读原文发现更多Java资源宝藏~

复制代码
复制代码
复制代码
复制代码
go 复制代码
点分享
点收藏
点点赞
点在看
相关推荐
.格子衫.3 小时前
Spring Boot 原理篇
java·spring boot·后端
多云几多3 小时前
Yudao单体项目 springboot Admin安全验证开启
java·spring boot·spring·springbootadmin
Swift社区4 小时前
LeetCode 394. 字符串解码(Decode String)
算法·leetcode·职场和发展
tt5555555555555 小时前
LeetCode进阶算法题解详解
算法·leetcode·职场和发展
Jabes.yang6 小时前
Java求职面试实战:从Spring Boot到微服务架构的技术探讨
java·数据库·spring boot·微服务·面试·消息队列·互联网大厂
聪明的笨猪猪6 小时前
Java Redis “高可用 — 主从复制”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
执尺量北斗6 小时前
[特殊字符] 基于 Qt + OpenGL 实现的入门级打砖块游戏
开发语言·qt·游戏
夏子曦6 小时前
C#内存管理深度解析:从栈堆原理到高性能编程实践
开发语言·c#
兮动人6 小时前
Spring Bean耗时分析工具
java·后端·spring·bean耗时分析工具
倔强青铜三6 小时前
苦练Python第64天:从零掌握多线程,threading模块全面指南
人工智能·python·面试