leetcode刷题第20天——1342,200,547

LeetCode算法题的解题方法
博客记录了LeetCode三道算法题的解题方法。包括将非负整数变成0的操作次数,有直接模拟和位运算优化两种方法;计算二维网格中岛屿数量,采用深度优先搜索;计算矩阵中省份数量,同样用DFS,根据城市连通性对算法稍作修改。

第二十天

1342 将数字变成0的操作次数

给你一个非负整数 num ,请你返回将它变成 0 所需要的步数。 如果当前数字是偶数,你需要把它除以 2 ;否则,减去 1 。

方法一

直接模拟。

class Solution {
    public int numberOfSteps(int num) {
        int count = 0;
        while (num != 0){
            ++count;
            if ((num & 1) == 1) --num;
            else num >>= 1;
        }
        return count;
    }
}
方法二 位运算优化

将减1操作转化成和0xfffffffe进行与运算。

class Solution {
    public int numberOfSteps(int num) {
        int count = 0;
        int ANDVALUE = Integer.MAX_VALUE - 1;
        while (num != 0){
            ++count;
            if ((num & 1) == 1) num &= ANDVALUE;
            else num >>= 1;
        }
        return count;
    }
}

200 岛屿数量

给你一个由 '1'(陆地)和'0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

方法 深度优先搜索

遍历整个图中的每一个节点,当遇到1时,对当前节点进行深搜,然后将访问过的节点都标记为已访问

class Solution {
public static boolean[][] isVisited;
    public static int xlength;
    public static int ylength;
    public static int[] dx = {0, 0, 1, -1};
    public static int[] dy = {1, -1, 0, 0};

    public int numIslands(char[][] grid) {
        int res = 0;
        xlength = grid.length;
        ylength = grid[0].length;
        isVisited = new boolean[xlength][ylength];
        for (int i = 0; i < xlength; ++i){
            for (int j = 0; j  < ylength; ++j){
                if (grid[i][j] == '1' && !isVisited[i][j]) {
                    depthFirstSearch(grid, i, j);
                    res++;
                }
            }
        }
        return res;
    }

    public static void depthFirstSearch(char[][] grid, int x, int y){
        if (isVisited[x][y]) return;
        isVisited[x][y] = true;
        for (int i = 0; i < 4; ++i){
            int newX = x + dx[i];
            int newY = y + dy[i];
            if (newX >= 0 && newX < xlength && newY >= 0 && newY < ylength &&
            grid[newX][newY] == '1' && !isVisited[newX][newY]){
                depthFirstSearch(grid, newX, newY);
            }
        }
    }
}

547 省份数量

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

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

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

返回矩阵中 省份 的数量。

方法 DFS

类比于地图的DFS,对DFS算法稍作修改,由于考虑的是城市之间的连通性,因此外层循环只需要从1遍历到n即可,内层调用DFS,对于已经访问过的节点i,将其标记为已访问即可。

class Solution {
    public static boolean[] isVisited;
    public int findCircleNum(int[][] isConnected) {
        int res = 0;
        isVisited = new boolean[isConnected.length];
        for (int i = 0; i < isConnected.length; ++i){
            if (!isVisited[i]){
                res++;
                depthFirstSearch(i, isConnected);
            }
        }
        return res;
    }
    
    public static void depthFirstSearch(int x, int[][] map){
        if (isVisited[x]) return;
        isVisited[x] = true;
        int length = map[x].length;
        for (int i = 0; i < length; ++i){
            if (map[x][i] == 1) depthFirstSearch(i, map); //城市i和联通 递归的去访问城市i的其他连通城市
        }
    }
}
### LeetCode 上 Python 的解思路及代码示例 #### 使用 Python 标准库的重要性 在解决 LeetCode时,熟悉 Python 标准库能够显著提高效率并简化代码逻辑。Python 提供了许多强大的内置模块和函数,这些工具可以帮助开发者快速处理复杂的数据结构算法[^1]。 以下是几个常见的 LeetCode 目及其对应的 Python 解法: --- #### 示例一:有效括号 (LeetCode 20) 此问是经典的栈操作案例。给定一个只包含 `'('` 和 `')'` 的字符串,判断该字符串中的括号是否合法。可以通过模拟栈的操作来验证每一对括号的匹配情况。 ```python def isValid(s: str) -> bool: stack = [] mapping = {")": "(", "}": "{", "]": "["} for char in s: if char in mapping.values(): stack.append(char) elif char in mapping.keys(): if not stack or stack.pop() != mapping[char]: return False return not stack ``` 上述代码利用了字典存储括号之间的映射关系,并通过列表作为栈的基础数据结构完成匹配过程[^2]。 --- #### 示例二:链表反转部分节点 (LeetCode 92 或 类似于引用中的第 4 条) 对于链表类目,通常涉及指针操作以及边界条件的严格控制。以下是一个简单的例子——局部翻转链表的部分节点。 输入样例: - 输入:`head = [1,2,3,4,5], k = 3` - 输出:`[3,2,1,4,5]` 解决方案如下所示: ```python class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next def reverseKGroup(head: ListNode, k: int) -> ListNode: dummy = jump = ListNode(0) dummy.next = l = r = head while True: count = 0 while r and count < k: # 判断是否有k个节点待反转 r = r.next count += 1 if count == k: # 如果满足,则执行反转 pre, cur = None, l for _ in range(k): # 反转l到r之前的k个节点 temp = cur.next cur.next = pre pre = cur cur = temp jump.next = pre # 连接已反转部分与剩余未反转部分 jump = l # 移动jump至当前组最后一个节点位置(l现在指向原组最后一位) l = r # 更新下一次循环起点为下一组的第一个节点(r此时位于下一组第一个节点处或者None) else: # 不足k个则无需继续反转 break jump.next = l # 将最后一段不足k个的节点连接起来 return dummy.next # 返回新头结点dummy.next ``` 这段代码实现了对指定长度子序列的逆序排列功能[^4]。 --- #### 示例三:二叉树遍历系列 (LeetCode 144/94/145) 针对二叉树的不同遍历方式(前序、中序、后序),可以采用递归方法轻松实现。下面分别展示这三种基本形式的具体实现方案。 ##### 前序遍历 (Preorder Traversal) ```python def preorderTraversal(root: TreeNode) -> list[int]: result = [] def dfs(node): if node is None: return result.append(node.val) # 访问根节点 dfs(node.left) # 左子树递归访问 dfs(node.right) # 右子树递归访问 dfs(root) return result ``` ##### 中序遍历 (Inorder Traversal) ```python def inorderTraversal(root: TreeNode) -> list[int]: result = [] def dfs(node): if node is None: return dfs(node.left) # 左子树递归访问 result.append(node.val) # 访问根节点 dfs(node.right) # 右子树递归访问 dfs(root) return result ``` ##### 后序遍历 (Postorder Traversal) ```python def postorderTraversal(root: TreeNode) -> list[int]: result = [] def dfs(node): if node is None: return dfs(node.left) # 左子树递归访问 dfs(node.right) # 右子树递归访问 result.append(node.val) # 访问根节点 dfs(root) return result ``` 以上三个版本均基于深度优先搜索策略构建而成,区别仅在于何时记录当前节点值的时间点不同而已[^3]。 --- ### 总结 通过对典型 LeetCode 目的解析可以看出,在日常过程中注重积累常用技巧非常重要;比如善用堆栈解决配对问、灵活运用链表双指针技术优化空间性能指标等等。同时也要不断巩固基础理论知识体系,这样才能更好地应对各种复杂的场景需求。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值