深信服笔试算法题

求会议房间数量

题目

大概意思是说输入几个会议的开始时间和结束时间,判断最少需要几个会议室。

思路

这题用快慢指针,之前做过类似的题。但是一直在调输入输出,写的心好累。下面的代码我用二维数组代替一下输入,我恨,看来在线OJ还是有必要练一下。

代码

public int minMeetingRooms(int[][] intervals) {
        if (intervals == null || intervals.length == 0) {
            return 0;
        }
        
        // 创建两个数组,分别保存会议的开始时间和结束时间
        int[] startTimes = new int[intervals.length];
        int[] endTimes = new int[intervals.length];
        
        // 填充开始时间和结束时间数组
        for (int i = 0; i < intervals.length; i++) {
            startTimes[i] = intervals[i][0];
            endTimes[i] = intervals[i][1];
        }
        
        // 对开始时间和结束时间进行排序
        Arrays.sort(startTimes);
        Arrays.sort(endTimes);
        
        int startPointer = 0, endPointer = 0;
        int rooms = 0, maxRooms = 0;
        
        // 使用两个指针分别扫描开始和结束时间
        while (startPointer < intervals.length) {
            if (startTimes[startPointer] < endTimes[endPointer]) {
                // 如果有会议开始但还没有结束,则需要新的会议室
                rooms++;
                startPointer++;
            } else {
                // 否则,结束一个会议,释放一个会议室
                rooms--;
                endPointer++;
            }
            // 更新最大房间数
            maxRooms = Math.max(maxRooms, rooms);
        }
        
        return maxRooms;
    }

求最长的无重复元素子数组

题目

就是求最长的无重复元素子数组

思路

博主肯定是昨天做动态规划魔怔了,一直在找状态转移方程,样例过了,总共A了百分之二十几。最后才想起要用滑动窗口,心碎了💔

代码

public int lengthOfLongestSubstring(int[] nums) {
        Set<Integer> set = new HashSet<>();  // 用于存储窗口中的元素
        int left = 0;  // 滑动窗口左边界
        int maxLength = 0;  // 最长的无重复子数组长度
        
        for (int right = 0; right < nums.length; right++) {
            // 如果遇到重复元素,缩小窗口
            while (set.contains(nums[right])) {
                set.remove(nums[left]);
                left++;
            }
            // 将当前元素添加到集合中
            set.add(nums[right]);
            // 更新最大长度
            maxLength = Math.max(maxLength, right - left + 1);
        }
        
        return maxLength;
    }

求覆盖子串的最小长度

题目

即给定一个字符串s和t,找出s中包含t中所有字符的最小长度

思路

做过类似的题目,前几天才做的,八分钟直接A了。

代码

public String minWindow(String S, String t) {
        char[] s = S.toCharArray();
        int m = s.length;
        int ansLeft = -1;
        int ansRight = m;
        int left = 0;
        int[] cntS = new int[128]; 
        int[] cntT = new int[128]; 
        for (char c : t.toCharArray()) {
            cntT[c]++;
        }
        for (int right = 0; right < m; right++) { 
            cntS[s[right]]++; 
            while (isCovered(cntS, cntT)) { 
                if (right - left < ansRight - ansLeft) { 
                    ansLeft = left; 
                    ansRight = right;
                }
                cntS[s[left++]]--; // 左端点字母移出子串
            }
        }
        return ansLeft < 0 ? "" : S.substring(ansLeft, ansRight + 1);
    }
 
    private boolean isCovered(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;
    }

求最短路径长度

题目

给定k,m,n,k代表体力,要从(0,0)走到(m,n)。请问是否能走到,如果可以给出最短路径的数量,不可以则输出0

思路

我直接BFS,结果A了50%,时间超限了。仔细一琢磨,要走出最短路径,那么只能往下或者往左走,一共走m+n步,感觉这是个数学问题。最后也没想出来,败在这里了。

chat了一下好像说我的做法没错,但是可以剪枝。我看了一下他提供的代码,时间复杂度和我的差不多。

 // 定义四个方向:上、下、左、右
    private static final int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    
    public int minPathCount(int m, int n, int k) {
        // 边界条件判断
        if (k < m + n) {
            return 0; // 如果体力不足以走到终点,直接返回 0
        }
        
        // 队列存储当前坐标及剩余体力
        Queue<int[]> queue = new LinkedList<>();
        // 记录每个点的最短路径数,初始值为 0
        int[][] pathCount = new int[m + 1][n + 1];
        // 用于记录每个点是否访问过,及体力消耗
        boolean[][] visited = new boolean[m + 1][n + 1];
        
        // 起点 (0, 0),初始体力为 k,路径数量为 1
        queue.offer(new int[]{0, 0, k});
        pathCount[0][0] = 1;
        visited[0][0] = true;
        
        // 记录步数
        int steps = 0;
        
        // 开始 BFS
        while (!queue.isEmpty()) {
            int size = queue.size();
            
            for (int i = 0; i < size; i++) {
                int[] current = queue.poll();
                int x = current[0];
                int y = current[1];
                int remainingK = current[2];
                
                // 如果到达终点 (m, n),返回最短路径数量
                if (x == m && y == n) {
                    return pathCount[m][n];
                }
                
                // 遍历四个方向
                for (int[] direction : directions) {
                    int newX = x + direction[0];
                    int newY = y + direction[1];
                    
                    // 确保新位置在范围内,体力充足,且未访问过
                    if (newX >= 0 && newX <= m && newY >= 0 && newY <= n && remainingK > 0) {
                        // 如果该位置未访问过,或体力更充足时可以再次访问
                        if (!visited[newX][newY] || remainingK - 1 > 0) {
                            queue.offer(new int[]{newX, newY, remainingK - 1});
                            visited[newX][newY] = true;
                            // 增加路径数量
                            pathCount[newX][newY] += pathCount[x][y];
                        }
                    }
                }
            }
            
            steps++; // 步数增加
        }
        
        // 无法到达终点,返回 0
        return 0;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值