博客记录-day156-力扣(单调栈)+Tomcat,高性能,高可用

137 阅读5分钟

一、力扣

1、只出现一次的数字

136. 只出现一次的数字

image.png

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

2、全排列 II

47. 全排列 II

image.png

class Solution {
    List<List<Integer>> res;
    List<Integer> path;
    int[] nums;
    int n;
    public List<List<Integer>> permuteUnique(int[] nums) {
        res=new ArrayList<>();
        path=new ArrayList<>();
        Arrays.sort(nums);
        this.nums=nums;
        n=nums.length;
        int[] vis=new int[n];
        dfs(vis);
        return res;
    }
    public void dfs(int[] vis){
        if(path.size()==n){
            res.add(new ArrayList<>(path));
            return;
        }
        for(int i=0;i<n;i++){
            if(vis[i]==1) continue;
            if(i>0&&nums[i]==nums[i-1]&&vis[i-1]==0) continue;
            path.add(nums[i]);
            vis[i]=1;
            dfs(vis);
            vis[i]=0;
            path.removeLast();
        }
    }
}

3、移掉 K 位数字-单调栈

402. 移掉 K 位数字

image.png

class Solution {
    public String removeKdigits(String num, int k) {
        // 使用双端队列模拟单调栈,存储最终结果的数字字符
        ArrayDeque<Character> stack = new ArrayDeque<>();
        int count = 0; // 记录已删除的数字个数
        
        for (int i = 0; i < num.length(); i++) {
            char temp = num.charAt(i);
            
            // 当还有删除机会,且栈非空,且栈顶元素比当前字符大时
            // 弹出栈顶元素(贪心策略:移除高位较大数,使整体更小)
            while (count < k && !stack.isEmpty() && stack.peek() > temp) {
                stack.pop();
                count++;
            }
            stack.push(temp); 
        }
        
        // 处理剩余删除次数(例如输入序列本身递增的情况)
        while (count < k) {
            stack.pop();
            count++;
        }
        
        // 构建结果字符串,跳过前导零
        StringBuilder res = new StringBuilder();
        while (!stack.isEmpty()) {
            char temp = stack.pollLast(); // 栈底到栈顶是数字的正确顺序
            // 跳过前导零,直到遇到第一个非零字符或结果为空
            if (temp == '0' && res.length() == 0)
                continue;
            res.append(temp);
        }
        
        // 处理结果全为零的特殊情况
        if (res.length() == 0)
            res.append('0');
        
        return res.toString();
    }
}

4、去除重复字母-单调栈

316. 去除重复字母

image.png

class Solution {
    public String removeDuplicateLetters(String s) {
        // 统计每个字符在字符串中剩余的出现次数
        int[] count = new int[26];
        for (var e : s.toCharArray()) {
            count[e - 'a']++;
        }

        // 记录当前已使用的字符,避免重复
        Set<Character> set = new HashSet<>();
        // 使用栈来维护结果字符串的字符顺序
        ArrayDeque<Character> stack = new ArrayDeque<>();

        for (int i = 0; i < s.length(); i++) {
            char temp = s.charAt(i);
            
            // 当前字符未被使用过时进行处理
            if (!set.contains(temp)) {
                // 当栈不为空,且栈顶字符大于当前字符,尝试弹出栈顶以优化字典序
                while (!stack.isEmpty() && stack.peek() > temp) {
                    char out = stack.peek();
                    // 若栈顶字符在后续字符串中仍存在,则可以弹出(后面还能添加回来)
                    if (count[out - 'a'] > 0) {
                        stack.pop();
                        set.remove(out); // 从已用集合中移除
                    } else {
                        break; // 栈顶字符后续不再出现,无法弹出,保持当前字符顺序
                    }
                }
                // 将当前字符入栈并标记为已使用
                stack.push(temp);
                set.add(temp);
            }
            // 处理当前字符后,剩余的该字符数量减1
            count[temp - 'a']--;
        }

        // 将栈中字符逆序拼接成最终结果(栈顶到栈底为逆序)
        StringBuilder res = new StringBuilder();
        while (!stack.isEmpty()) {
            res.append(stack.pollLast());
        }
        return res.toString();
    }
}

5、零钱兑换

322. 零钱兑换

image.png

dp[i][j]为以0-i的硬币实现总和为j的最少硬币数。

class Solution {
    public int coinChange(int[] coins, int amount) {
        int n=coins.length;
        int[][] dp=new int[n+1][amount+1];
        for(int i=0;i<=n;i++){
            Arrays.fill(dp[i],Integer.MAX_VALUE/2);
        }
        dp[0][0]=0;
        for(int j=0;j<=amount;j++){
            for(int i=0;i<n;i++){
                if(j<coins[i]){
                    dp[i+1][j]=dp[i][j];
                }else{
                    dp[i+1][j]=Math.min(dp[i][j],dp[i+1][j-coins[i]]+1);
                }
            }
        }
        return dp[n][amount]==Integer.MAX_VALUE/2?-1:dp[n][amount];
    }
}

6、打家劫舍 II

213. 打家劫舍 II

image.png

class Solution {
    public int rob(int[] nums) {
        int n = nums.length;
        if (n == 0) return 0;
        // 情况1:偷第一个房子,因此不能偷最后一个。计算从第2个到倒数第2个的最大值,并加上第一个房子
        // 情况2:不偷第一个房子,计算从第1个到最后一个的最大值
        // 取两种情况的最大值
        return Math.max(nums[0] + count(nums, 2, n - 2), count(nums, 1, n - 1));
    }

    public int count(int[] nums, int left, int right) {
        int pre2 = 0;   // 上上最大金额
        int pre1 = 0;    // 上个最大金额
        for (int i = left; i <= right; i++) {
            // 当前房屋的最大金额:选择偷(上上个 + 当前金额)或不偷(上个)的较大值
            int ans = Math.max(pre1, pre2 + nums[i]);
            // 更新状态:前一个不偷的状态变为前一个偷的状态,当前状态变为新计算的ans
            pre2 = pre1;
            pre1 = ans;
        }
        return pre1; // 返回最终计算的最大金额
    }
}

二、语雀-Tomcat

1、Tomcat的启动流程是怎样的?

✅Tomcat的启动流程是怎样的?

image.png

2、Tomcat中有哪些类加载器?

✅Tomcat中有哪些类加载器?

image.png

image.png

image.png

3、为什么Tomcat可以把线程数设置为200,而不是N+1?

✅为什么Tomcat可以把线程数设置为200,而不是N+1?

image.png

4、Tomcat处理请求的过程是怎么样的?

✅Tomcat处理请求的过程是怎么样的?

image.png

5、过滤器和拦截器的区别是什么?

✅过滤器和拦截器的区别是什么?

image.png

image.png

6、介绍一下Tomcat的IO模型?

✅介绍一下Tomcat的IO模型?

image.png

7、Tomcat与Web服务器(如Apache)之间的关系是什么?

✅Tomcat与Web服务器(如Apache)之间的关系是什么?

image.png

8、Tomcat的类加载机制是怎么样的

✅Tomcat的类加载机制是怎么样的?

image.png

image.png

1. 为什么打破双亲委派

image.png

2. 如何避免重复加载

image.png

三、语雀-高性能

1、如何设计一个高性能的分布式系统

✅如何设计一个高性能的分布式系统

image.png

image.png

2、什么是QPS,什么是RT?

✅什么是QPS,什么是RT?

image.png

image.png

3、服务端接口性能优化有哪些方案?

✅服务端接口性能优化有哪些方案?

image.png

image.png

image.png

image.png

4、什么是布隆过滤器,实现原理是什么?

✅什么是布隆过滤器,实现原理是什么?

image.png

image.png

1. 应用场景

image.png

5、什么是读写分离?如何实现?

✅什么是读写分离?如何实现?

image.png

1. 如何做读写的分流?

image.png

image.png

6、读写分离遇到主从延迟怎么办?

✅读写分离遇到主从延迟怎么办?

1. 读请求分类

image.png

2. 强制读主库

image.png

7、说下什么是p90,p95,P99?

✅说下什么是p90,p95,P99?

image.png

8、布隆过滤器有什么缺点,如何解决?

✅布隆过滤器有什么缺点,如何解决?

1. 误判

image.png

1.1 二次查询

image.png

2. 无法删除元素

image.png

四、语雀-高可用

1、什么是SLA?

✅什么是SLA?

image.png

2、什么是冷备、热备,暖备?

✅什么是冷备、热备,暖备?

image.png

3、如何设计一个高可用架构?

✅如何设计一个高可用架构?

image.png

image.png

image.png

4、什么是异地多活?

✅什么是异地多活?

image.png

5、什么是压测,怎么做压测?

✅什么是压测,怎么做压测?

image.png

6、单机压测到300QPS,10台就能抗住3000QPS吗?

✅单机压测到300QPS,10台就能抗住3000QPS吗?

image.png