LeetCode 704, 290, 200

704. 二分查找

题目链接

704. 二分查找

标签

数组 二分查找

思路

这道题是 二分查找 最经典的一道题,掌握了本题的思想就进入了 二分 思想的大门。

二分查找 指的是每次查找把区间分为两半,然后将目标值 target 与区间中点 mid 对应的值 nums[mid] 作比较,由于数组是 升序 的,所以如果 target 小于 nums[mid],则下一轮查找的区间为左子区间(因为只有在左子区间才能找到比 nums[mid] 小的数);如果 target 大于 nums[mid],则下一轮查找的区间为右子区间(因为只有在右子区间才能找到比 nums[mid] 大的数);如果 target 等于 nums[mid],则直接返回 mid 作为 target 的下标。当查找区间长度不够0时,退出查找,返回 -1 表示没有找到。

注意:二分查找 的前提是 数组有序,如果数组是无序的,那么将无法每次排除掉半个区间。

代码

class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length - 1; // left和right分别为查找区间的左、右索引
        while (left <= right) { // 当查找区间长度不够0时,退出查找
            int mid = left + (right - left >> 1); // 获取区间中间元素的索引
            if (target < nums[mid]) { // 如果 target 小于 nums[mid]
                right = mid - 1; // 将区间的 右端点 移动到 中点-1 处,下一轮查找的区间为左子区间
            } else if (target > nums[mid]) { // 如果 target 大于 nums[mid]
                left = mid + 1; // 将区间的 左端点 移动到 中点+1 处,下一轮查找的区间为右子区间
            } else { // 如果 target 等于 nums[mid]
                return mid; // 返回 mid 作为 target 的下标
            }
        }
        return -1; // 没有找到 target,返回 -1
    }
}

290. 单词规律

题目链接

290. 单词规律

标签

哈希表 字符串

思路

本题与 205. 同构字符串 很像,要么使用 建立双向索引 的方法,要么使用 查找第一次出现索引 的方法。上面那道题是用 字符与字符 之间的索引比较,而本题则是使用 字符与字符串 之间的索引比较。

建立双向索引 的方法是一种容易想到的方法,它的核心思想就是分别使用两个 Map,分别记录从 pattern中的字符 到 s中的字符串 的映射和从 s中的字符串 到 pattern中的字符 的映射,然后截取每个 字符 与 字符串,查看 字符 与 字符串 能否 互相映射,如果 字符 或 字符串 没有映射,则先建立映射。

相比之下,查找第一次出现索引 这种方法更难想到,因为它更偏向 底层,上面的方法使用 Map 存储了 每个字符对应的第一个字符串 或 每个字符串对应的第一个字符,其实不需要这么复杂,只需要存储 每个字符第一次出现的位置 和 每个字符串第一次出现的位置 即可,因为比较 字符 与 字符串 能否 互相映射 的更底层就是 比较 字符第一次出现的索引 与 字符串第一次出现的索引 是否一致。

思路明确了:先将字符串 s 用空格分割为 list;然后检查 pattern中字符的个数 与 list中字符串的个数 是否相等,如果这两个值不相等,那就说明 patterns 不遵循相同的规律,返回 false;接着获取 pattern 中每个字符第一次出现的索引 和 list 中每个字符串第一次出现的索引,如果它们不同,则说明 patterns 不遵循相同的规律,返回 false;如果能比较完全部 字符 与 字符串 都不返回 false,那么说明 patterns 遵循相同的规律,返回 true

代码

class Solution {
    public boolean wordPattern(String pattern, String s) {
        List<String> list = List.of(s.split(" ")); // 用 空格 分割,将 pattern 分割到一个 List 集合中
        int n = pattern.length(); // 获取 s 的长度
        if (n != list.size()) { // 如果 pattern中字符的个数 与 list中字符串的个数 不相同
            return false; // 则 pattern 和 s 不遵循相同的规律,返回 false
        }
        
        for (int i = 0; i < n; i++) { // 遍历比较每个 字符 与 字符串
            int pi = pattern.indexOf(pattern.charAt(i); // 获取 本字符 第一次出现的索引
            int si = list.indexOf(list.get(i)); // 获取 本字符串 第一次出现的索引
            if (pi != si) { // 如果 字符第一次出现的索引 与 字符串第一次出现的索引 不同
                return false; // 则 pattern 和 s 不遵循相同的规律,返回 false
            }
        }
        return true; // pattern 和 s 遵循相同的规律,返回 true
    }
}

200. 岛屿数量

题目链接

200. 岛屿数量

标签

深度优先搜索 广度优先搜索 并查集 数组 矩阵

思路

本题的目标是 找到岛屿的个数,岛屿的定义是 一片连通的'1'

题目可没有说不能修改原地图,所以可以遍历整个地图,如果找到陆地(该元素等于 '1'),就让岛屿数加一,并使用 深度优先搜索 淹没这块陆地所在的岛屿(将这片连通的 '1' 全部变成 '0'),之后接着遍历,直到遍历完整个地图。

代码

class Solution {
    public int numIslands(char[][] grid) {
        int res = 0;
        int m = grid.length, n = grid[0].length;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == '1') { // 如果i和j指向的是陆地
                    res++; // 则岛屿数加一
                    flood(grid, i, j); // 淹没这整座岛屿
                }
            }
        }
        return res;
    }
    // 在grid中,淹没 含有i和j指向陆地的 整座岛屿
    private void flood(char[][] grid, int i, int j) {
        grid[i][j] = '0'; // 先淹没i和j指向的陆地
        for (int k = 0; k < 4; k++) {
            int ki = i + dir[k][0], kj = j + dir[k][1];
            if (ki >= 0 && ki < grid.length && kj >= 0 && kj < grid[0].length // 如果ki和kj没有越界
                    && grid[ki][kj] == '1') { // 并且ki和kj指向的元素为'1',即ki和kj指向陆地
                flood(grid, ki, kj);; // 则淹没ki和kj指向的陆地
            }
        }
    }
    private int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // 方向数组,分别为 向右、向下、向左、向上
}
  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值