热题100_20230505

155、最小栈(栈)

题目说明

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

MinStack() 初始化堆栈对象。
void push(int val) 将元素val推入堆栈。
void pop() 删除堆栈顶部的元素。
int top() 获取堆栈顶部的元素。
int getMin() 获取堆栈中的最小元素。

解题思路

题目需要我们去维护一个最小值,但是可能出现的问题是,最小值被移除之后,次小值变成了最小值,但我们并不知道在之前的序列中次小值是多少。因此我们可以换一个思路,理解为每一个数插入之后(每一层)都有一个最小值,我们去维护每一层的最小值就可以了(因为出栈必须从栈顶到栈底)

因此我们可以选择一个辅助栈,并在辅助栈的栈底先插入一个Integer.MAX_VALUE,此后每进入一个数,辅助栈也会进入一个最小值,用新进入栈的数和辅助栈的栈顶进行比较,如果新的数小则辅助栈选择新的数入栈,否则选择原先的栈顶入栈。

public void push(int val) {
    minstack.push(val);
    if (val < support.peek()) {
        support.push(val);
    } else {
        support.push(support.peek());
    }
}

136、只出现一次的数字(异或)

题目说明

给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间

解题思路1:异或

明确的提出了,每个元素只出现两次,那么我们需要思考“两次”可以带来什么,两次可以如何消掉这个数字。我们可以采用异或的方法,如果使用异或,相同的数字异或之后会等于0,那么到最后只会剩下只出现一次的元素(出现两次的都异或成0了)

我的狗脑子真的想不出异或啊啊啊啊啊啊啊啊啊啊

解题思路2:哈希

用HashSet存储出现过的每一个数字,如果数字不存在则加入set,如果存在则将其删除。到最后HashSet只会有一个元素,即为结果

153、寻找旋转排序数组中的最小值(二分)

题目说明

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]] 。

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

解题思路

如果发生旋转的话,可以理解为数组出现了一个谷底(也可能没有谷底最小值仍在最左边),那么我们可以使用二分法来判定一个问题,即谷底出现在哪一边。

求出[l, r]序列的中间位置mid,拿mid处的数字和r处的数字进行比较,如果mid处的数字小于r处的数字,说明mid到r这段右边序列是有序的,谷底会出现在左边(也可能就是mid的位置),否则说明左边是有序的,谷底出现在右边且不可能是mid的位置

while (l < r) {
    int mid = l + (r - l) / 2;
    if (nums[mid] < nums[r]) { // 右边有序,说明谷底在左边,可能就是mid的位置
        r = mid;
    } else { // 左边有序右边不有序,说明谷底在右边且不可能是mid的位置
        l = mid + 1;
    }
}

4、寻找两个正序数组的中位数(二分)

题目说明

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

算法的时间复杂度应该为 O(log (m+n)) 。

解题思路1:合并

合并可以合并全部也可以合并一半,合并一半的话可以省一半的时间复杂度,根据元素数量是奇数还是偶数来判定中位数取最后一位还是两位的平均值

解题思路2:二分法

看到题目需要的时间复杂度是O(log (m+n))

547、省份数量(图)

题目说明

有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。

省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。

给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。

返回矩阵中 省份 的数量。

解题思路1:DFS

每次都抓住一条城市路径一直向下遍历,用对角线上的位置判定该城市是否被访问过,如果被访问了则置0,没有则继续向下深入遍历,并对被遍历过的边置0处理(防止重复遍历)。在主函数中对i个城市进行遍历,每次遍历之前都先判断对角线上的元素是否为0(即是否被访问过)

public void dfs(int[][] isConnected, int cur) {
    // 不处理对角线不然卡死
    if (isConnected[cur][cur] != 1) { // 这个城市已经被处理过和其他省连在一起了
        return;
    }
    for (int i = 0; i < isConnected.length; i++) {
        if (isConnected[cur][i] == 1) {
            isConnected[cur][i] = 0; // 说明cur和i是一个省的
            isConnected[i][cur] = 0;
            dfs(isConnected, i);
            isConnected[i][i] = 0;
        }
    }
}

解题思路2:BFS

用一个visit数组对各个城市进行标记,如果城市未被访问且与之前的城市相连则进入队列,每次都把直接与该城市相连的城市进入到队列中,直到队列为空。对i个城市进行循环,每次判断是否是新的省份前都先确认一遍该城市是否被访问过

for (int i = 0; i < isConnected.length; i++) {
    if (visit[i]) {
        continue;
    }
    province++;
    queue.offer(i);
    visit[i] = true;
    while (!queue.isEmpty()) {
        int city = queue.poll();
        for (int j = 0; j < isConnected.length; j++) {
            if (!visit[j] && isConnected[city][j] == 1) {
                queue.offer(j);
                visit[j] = true;
            }
        }
    }
}

394、字符串解码

题目说明

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

解题思路1:递归

  • 当遇到数字时,对数字不断的加起来存储在multi中(注意可能是多位的数字)

  • 当遇到'['时,说明需要用之前的multi与后面的字符串进行相乘,那么进入下一层的递归中

  • 当遇到']'时,说明这一段处理完了,要将这一段的结果返回回去和multi相乘

  • 当遇到字符串时正常的连接上去即可

值得注意的是,因为进入了下一层之后,index的值也在不断的变化,等到返回上一层结果之后要注意index也要跟着返回上去,避免重复处理

public String[] dfs(String s, int i) {
    StringBuilder res = new StringBuilder();
    int multi = 0;
    while (i < s.length()) {
        if (s.charAt(i) >= '0' && s.charAt(i) <= '9') {
            multi = multi * 10 + (s.charAt(i) - '0');
        } else if (s.charAt(i) == '[') {
            String[] tmp = dfs(s, i + 1); // 从下一个位置开始获取字符串
            i = Integer.parseInt(tmp[0]); // 记录下以后a要往哪里走
            while (mu/; lti > 0) {
                res.append(tmp[1]);
                multi--;
            }
        } else if (s.charAt(i) == ']') {
            return new String[] {String.valueOf(i), res.toString()};
        } else {
            res.append(s.charAt(i));
        }
        i++;
    }
    return new String[] {res.toString()};
}
posted @   XCCX0824  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示