Leetcode 易错题整理(三)73. 77. 78. 81. 90. 95.105. 130.

news2024/9/23 11:17:55

73. 矩阵置零

给定一个 *m* x *n* 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法**。**

示例 1:

img

输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
输出:[[1,0,1],[0,0,0],[1,0,1]]

笨方法:先遍历一次整个数组,获取到所有0位置,第二次把这里面所有0位置数字横竖都变为0.

原地算法:我们可以把这一行列是否有0的信息存到第一行和第一列,比如该数组第一次扫描完结果为:

1 0 1

0 0 1

1 1 1

上和左两个0表示这一行这一列后面应当被置零。第二次扫描的时候就只扫描第一行和第一列,把为0的行列头这一行列都置为0即可。

但是这样会出现一个问题,就是比如第一行第一列如果出现了0,那么第一行 第一列也要被置为0. 但是我们无法判断这个0是本来就有的还是第一次遍历的时候数组中的元素传递过来的。

解决办法是我们再单独用两个变量存储第一行第一列是否存在0的信息,如果存在,那么最后再把第一行第一列置0.

class Solution {
    public void setZeroes(int[][] matrix) {
        boolean fstLineHas0=false;
        boolean fstColumnHas0=false;
        int xLen=matrix.length,yLen=matrix[0].length;
        for(int i=0;i<xLen;i++){
            if(matrix[i][0]==0){
                fstColumnHas0=true;
                break;
            }
        }
        for(int j=0;j<yLen;j++){
            if(matrix[0][j]==0){
                fstLineHas0=true;
                break;
            }
        }
        for(int i=1;i<xLen;i++){
            for(int j=1;j<yLen;j++){
                if(matrix[i][j]==0){
                    matrix[i][0]=0;
                    matrix[0][j]=0;
                }
            }
        }
        for(int i=1;i<xLen;i++){
            if(matrix[i][0]==0){
                for(int j=1;j<yLen;j++)matrix[i][j]=0;
            }
        }
        for(int j=1;j<yLen;j++){
            if(matrix[0][j]==0){
                for(int i=1;i<xLen;i++)matrix[i][j]=0;
            }
        }
        if(fstColumnHas0)for(int i=0;i<xLen;i++)matrix[i][0]=0;
        if(fstLineHas0)for(int j=0;j<yLen;j++)matrix[0][j]=0;
    }
}

77. 组合

给定两个整数 nk,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

示例 1:

输入:n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]

示例 2:

输入:n = 1, k = 1
输出:[[1]]

一开始我就是写了一个简单的递归遍历,自然是超时了。

public void dfs(List<List<Integer>> resList, int n, int k){
        
        if(k==0)return;
        if(resList.size()==0){
           for(int i=1;i<=n;i++){
               List<Integer> tempList=new ArrayList<>();
               tempList.add(i);
               resList.add(tempList);
           }
           dfs(resList,n,k-1);
        }
        else if(n<resList.get(0).size()+k){
            resList=new ArrayList<>();
            return;
        }
        else {
            int len=resList.size();
            List<Integer> fstList=resList.get(0);
            int max=fstList.get(fstList.size()-1);
            for(int i=0;i<len;i++){
                
                for(int j=max+1;j<=n;j++){
                    List<Integer> tempList=new ArrayList<>(resList.get(0));
                    tempList.add(j);
                    resList.add(tempList);
                }
                resList.remove(0);
            }
            dfs(resList,n,k-1);
        }
    }

后来看了官方题解,我没必要这样频繁地存取元素。

public void dfs1(List<List<Integer>> resList, List<Integer>tempList, int n, int k, int cur){
        
        if(tempList.size()==k){
            resList.add(new ArrayList<>(tempList));
            return;
        }
        else if(tempList.size()+(n-cur+1)<k){
            return;
        }
        else {
            tempList.add(cur);
            dfs1(resList,tempList,n,k,cur+1);
            tempList.remove(tempList.size()-1);
            dfs1(resList,tempList,n,k,cur+1);
        }
    }

只有一个 tempList 元素在不停地动态变化,我们只需要在其长度到达 k 时复制一份传入 resList 列表即可。

对于每次遍历的元素,我们选择是保留或忽略此元素,这样从所有元素都保留的结果到所有元素都忽略的结果都能考虑到。

这种算法叫做剪枝。当当前这个分支已经无法满足题意,或者已经可以判定非最优解了,就可以把这个枝剪掉,不要继续走了。

78. 子集

找出给定集合的所有子集(从空集到他自身都要找到)。

这个和上面的深度遍历是一个道理,区别在于“什么时候是一轮判断完成的标志”。上面一题是 tempList 长度到达 k 固定长度的时候结束并存入本轮循环的 list,此题可以是扫描完全数组时存入。

class Solution {
    List<List<Integer>> resList=new ArrayList<>();
    List<Integer> tempList=new ArrayList<>();
    public List<List<Integer>> subsets(int[] nums) {
        dfs(0,nums);
        return resList;
    }

    public void dfs(int cur, int[] nums){
        if(cur==nums.length){
            resList.add(new ArrayList<>(tempList));
            return;
        }
        tempList.add(nums[cur]);
        dfs(cur+1,nums);
        tempList.remove(tempList.size()-1);
        dfs(cur+1,nums);
    }
}

81. 搜索旋转数组 II

已知存在一个按非降序排列的整数数组 nums ,数组中的值不必互不相同。

在传递给函数之前,nums 在预先未知的某个下标 k0 <= k < nums.length)上进行了 旋转 ,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,4,4,5,6,6,7] 在下标 5 处经旋转后可能变为 [4,5,6,6,7,0,1,2,4,4]

给你 旋转后 的数组 nums 和一个整数 target ,请你编写一个函数来判断给定的目标值是否存在于数组中。如果 nums 中存在这个目标值 target ,则返回 true ,否则返回 false

你必须尽可能减少整个操作步骤。

示例 1:

输入:nums = [2,5,6,0,0,1,2], target = 0
输出:true

主要可能出现的问题:形如 [1,1,1,1,3,1,1,1,1,1,1,1,1] 这样的数组,我们不确定特殊数处在什么位置。这样就不能用传统二分法一砍砍一半了。

class Solution {
    public boolean search(int[] nums, int target) {
        int left=0,right=nums.length-1;
        while(left<=right){
            int mid=(left+right)/2;
            if(nums[mid]==target)return true;
            else if(nums[left]==nums[mid]&&nums[right]==nums[mid]){//头尾缩减一点,来逐步排查特殊数部分
                left++;
                right--;
            }
            else if(nums[mid]<=nums[right]){
                if(nums[mid]<target&&nums[right]>=target)left=mid+1;//右侧自增,且 target 落在右侧区间中
                else right=mid-1;
                
            }
            else {
                if(nums[mid]>target&&nums[left]<=target)right=mid-1;//左侧自增,且 target 落在左侧区间中
                else left=mid+1;
            }
        }
        return false;
    }
}

90. 子集 II

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

示例 1:

输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]

和之前的组合总和题有些类似,主要是注意不要重复。

解法:统一规定,如果此次递归访问的元素和上一次一样,且上一次没有包含这个元素,那么本次递归不再尝试加入此元素。

class Solution {
    List<List<Integer>> resList=new ArrayList<>();
    List<Integer> tempList=new ArrayList<>();
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        Arrays.sort(nums);
        dfs(nums, 0,false);
        return resList;
    }

    public void dfs(int[] nums, int cur,boolean visited){
        if(cur==nums.length){
            resList.add(new ArrayList<Integer>(tempList));
            return;
        }
        dfs(nums, cur+1,false);//可以放弃此元素继续递归
        if(cur>0&&nums[cur-1]==nums[cur]&&(!visited))return;//但是不能使用重复的元素,不然就和上一轮循环重复了。
        tempList.add(nums[cur]);
        dfs(nums, cur+1,true);
        tempList.remove(tempList.size()-1);
        
    }
}

95. 不同的二叉搜索树 II

给你一个整数 n ,请你生成并返回所有由 n 个节点组成且节点值从 1n 互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。

示例 1:

img

输入:n = 3
输出:[[1,null,2,null,3],[1,null,3,2],[2,1,3],[3,1,null,null,2],[3,2,null,1]]

还是有规律的。我们每次遍历选取一个节点作为根节点,左边的树递归生成左子树,右边递归生成右子树,两树再合并到根节点左右之下。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<TreeNode> generateTrees(int n) {
        if(n==0)return new LinkedList<TreeNode>();
        return generateTree(1,n);
    }

    public List<TreeNode> generateTree(int start, int end){
        List<TreeNode> resList=new LinkedList<>();
        if(start>end){
            resList.add(null);
            return resList;
        };
        for(int i=start;i<=end;i++){
            List<TreeNode> leftTree=generateTree(start,i-1);
            List<TreeNode> rightTree=generateTree(i+1,end);
            for(TreeNode left:leftTree){
                for(TreeNode right:rightTree){
                    TreeNode root=new TreeNode(i);
                    root.left=left;
                    root.right=right;
                    resList.add(root);
                }
            }
        }
        return resList;
        
    }
}

105. 从前序与中序遍历序列构造二叉树

给定两个整数数组 preorderinorder ,其中 preorder 是二叉树的先序遍历inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

示例 1:

img

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

主要是一个思想。

preorder:形如 root, x, x, x, x..., x

inorder:形如 x, x, x, x... root, x, x... x

那么我们每次找到 root 和左子树右子树,递归继续操作即可。

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return f(preorder, inorder, 0,preorder.length-1,0,inorder.length-1);
    }

    public TreeNode f(int[] preorder, int[] inorder, int preLeft, int preRight, int inLeft, int inRight){
        if(preLeft>preRight)return null;
        TreeNode root=new TreeNode(preorder[preLeft]);
        int i=inLeft;
        while(inorder[i]!=preorder[preLeft])i++;
        root.left=f(preorder,inorder,preLeft+1,i-inLeft+preLeft,inLeft,i-1);
        root.right=f(preorder,inorder,preLeft+(i-inLeft)+1,preRight,i+1,inRight);
        return root;
    }
}

130. 被围绕的区域

给你一个 m x n 的矩阵 board ,由若干字符 'X''O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O''X' 填充。

示例 1:

img

输入:board = [["X","X","X","X"],["X","O","O","X"],["X","X","O","X"],["X","O","X","X"]]
输出:[["X","X","X","X"],["X","X","X","X"],["X","X","X","X"],["X","O","X","X"]]
解释:被围绕的区间不会存在于边界上,换句话说,任何边界上的 'O' 都不会被填充为 'X'。 任何不在边界上,或不与边界上的 'O' 相连的 'O' 最终都会被填充为 'X'。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。

解决办法:首先我们扫描一下所有边界,对于其中值 =O 的元素,赋值=A 表示要保留,递归判断其上下左右中出现 O 的地方也作同样处理。

然后遍历整个数组,把 A 的部分改为 O,把 X O 都改成 X。

class Solution {
    public void solve(char[][] board) {
        int lineLen=board.length;
        int columnLen=board[0].length;
        for(int i=0;i<lineLen;i++){
            dfs(board,i,0);
            dfs(board,i,columnLen-1);
        }
        for(int i=0;i<columnLen;i++){
            dfs(board,0,i);
            dfs(board,lineLen-1,i);
        }
        for(int i=0;i<lineLen;i++){
            for(int j=0;j<columnLen;j++){
                if(board[i][j]=='A')board[i][j]='O';
                else board[i][j]='X';
            }
        }
    }

    public void dfs(char[][] board, int i, int j){
        if(i<0||i>=board.length)return;
        if(j<0||j>=board[0].length)return;
        if(board[i][j]=='A'||board[i][j]=='X')return;
        else board[i][j]='A';
        dfs(board,i,j-1);
        dfs(board,i,j+1);
        dfs(board,i-1,j);
        dfs(board,i+1,j);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/986460.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在很多公司里面会使用打tag的方式保留版本

&#xff1a;git tag|grep "xxx-dev“等分支来查看 2&#xff1a;git cherry-pick XXXXX 然后就是查看有冲突这些 git status 会出现相关的异常 然后解决相关的冲突 git add . git cherry-pick --continue git push XXX HEAD:refs/for/XXX 第一&#xff1a;git ta…

Excel自学三部曲_Part3:Excel工作场景分析实战

文章目录 一、Excel工作场景与知识点总结1. 学哪个Excel?&#xff08;1&#xff09;学习哪个版本的Excel?&#xff08;2&#xff09;Excel和WPS到底学哪个&#xff1f; 2. 怎么用Excel?&#xff08;1&#xff09;低量级数据的存储&#xff08;2&#xff09;一次性的数据处理…

解决使用torchstat时报错“AttributeError: module ‘numpy‘ has no attribute ‘long‘”等问题

背景 首先直接使用pip install torchstat安装。 使用torchstat查看模型参数和flops&#xff1a; from torchstat import stat stat(model.to(cpu), (2, 32, 32)) # 这里第二个参数取决于自己的模型输入大小报错1 运行报错如下&#xff1a; 核心错误为&#xff1a; “Attri…

uniapp分包 解决分多个包的问题

1. 分包可以分很多个, 但是在"optimization": { "subPackages": true } 里面只能写一个, 2. 想分多个包 , 在 pages.json 里面 的 subPackages 里面继续加 第三个 第四个即可 3. 保存之后 创建页面就可以看见多个包了

异常的顶级理解

目录 1.异常的概念与体系结构 1.1异常的体系结构 1.2异常的举例 1.3错误的举例 2.异常的分类 2.1编译时异常 2.2运行时异常 3.异常的处理 3.1异常的抛出throw 3.2try-catch捕获并处理 3.3finally 3.4 异常声明throws 4.自定义异常类 1.异常的概念与体系结构 1.1异常的…

BMS电池管理系统——什么是BMS(一)

BMS电池管理系统 文章目录 BMS电池管理系统前言一、BMS是什么&#xff1f;二、BMS的主要功能模块1.采样及测量功能2.状态估计及预测功能3.控制及管理功能4.通讯和诊断功能 总结 前言 作为一名电气专业的学生&#xff0c;大学里学了很多嵌入式相关的知识&#xff0c;首先要明确…

便捷高效的一键发布成绩

今天我要给大家推荐一个非常实用的教育工具——易查分。作为一名教育工作者&#xff0c;我深知每次发布成绩都是一项繁琐而重要的任务。然而&#xff0c;有了易查分&#xff0c;这一切都变得轻松高效起来。让我来告诉各位老师&#xff0c;易查分是如何实现一键发布成绩的&#…

Xilinx IDDR与ODDR原语的使用

文章目录 ODDR原语1. OPPOSITE_EDGE 模式2. SAME_EDGE 模式 ODDR原语 例化模板&#xff1a; ODDR #(.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE" .INIT(1b0), // Initial value of Q: 1b0 or 1b1.SRTYPE("SYNC…

Scrapy的基本介绍、安装及工作流程

一.Scrapy介绍 Scrapy是什么&#xff1f; Scrapy 是用 Python 实现的一个为了爬取网站数据、提取结构性数据而编写的应用框架(异步爬虫框架) 通常我们可以很简单的通过 Scrapy 框架实现一个爬虫&#xff0c;抓取指定网站的内容或图片。 Scrapy使用了Twisted异步网络框架&…

【LeetCode题目详解】第九章 动态规划 part05 1049. 最后一块石头的重量 II 494. 目标和 474.一和零(day43补)

本文章代码以c为例&#xff01; 一、力扣第1049题&#xff1a;最后一块石头的重量 II 题目&#xff1a; 有一堆石头&#xff0c;用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。 每一回合&#xff0c;从中选出任意两块石头&#xff0c;然后将它们一起粉碎…

C++学习记录——삼십삽 STL空间配置器

文章目录 1、概念2、使用3、容器上的体现 1、概念 我们先看malloc&#xff0c;malloc是创建在堆上的&#xff0c;虽然malloc可以申请内存&#xff0c;但也有限制&#xff0c;windows下用VirtualAlloc可以直接向堆申请内存&#xff0c;Linux中则是brk&#xff0c;不过这两个效率…

HCIA自学笔记01-传输介质

通信网络除了包含通信设备本身之外&#xff0c;还包含连接这些设备的传输介质&#xff0c;如同轴电缆、双绞线和光纤等。不同的传输介质具有不同的特性&#xff0c;这些特性直接影响到通信的诸多方面&#xff0c;如线路编码方式、传输速度和传输距离等。 简单网络&#xff1a;…

✔ ★算法基础笔记(Acwing)(一)—— 基础算法(20道题)【java版本】

基础算法 一、快速排序1. 快速排序例题2. 第k个数( 快速选择 ) ✔ ✔1.31★快排二刷总结( 4点 ) 二、归并排序1. 归并排序模板题 ✔ ✔1.31★二刷总结 ★2. 逆序对的数量 ✔ ✔1.31★二刷总结 三、二分1. 数的范围 ✔1.31★二刷总结(mid > x 则是 输出最左边一个)第一个大于…

【操作系统】聊聊Linux内存工作机制

内存主要是用来存储系统和应用程序的指令、数据、缓存等 内存映射 内存是需要安全机制保护的&#xff0c;所以只有内核才可以直接访问物理内存。进程如果要访问内存需要通过独立的虚拟地址空间。 虚拟地址空间其实包含两部分。一部分是内核空间&#xff0c;另一部分就是用户…

搭建RabbitMQ消息服务,整合SpringBoot实现收发消息

作者主页&#xff1a;Designer 小郑 作者简介&#xff1a;3年JAVA全栈开发经验&#xff0c;专注JAVA技术、系统定制、远程指导&#xff0c;致力于企业数字化转型&#xff0c;CSDN博客专家&#xff0c;蓝桥云课认证讲师。 目录 一、前言1.1 什么是消息队列1.2 RabbitMQ 是什么1.…

【AI】机器学习——线性模型(线性回归)

线性模型既能体现出重要的基本思想&#xff0c;又能构造出功能更加强大的非线性模型 文章目录 3.1 线性模型3.1.1 数据3.1.2 目标/应用 3.2 线性回归3.2.1 回归模型历史3.2.2 回归分析研究内容回归分析步骤 3.2.3 回归分析分类3.2.4 回归模型3.2.5 损失函数梯度下降法一元回归模…

【数据仓库基础(二)】数据仓库架构

文章目录 一. 基本架构二. 主要数据仓库架构1. 数据集市架构1.1. 独立数据集市1.2. 从属数据集市1.3. Inmon企业信息工厂架构 2. Kimball数据仓库架构3. 混合型数据仓库架构 三. 操作数据存储&#xff08;ODS&#xff09; 一. 基本架构 架构是指系统的一个或多个结构。结构中包…

stride与padding对输出尺寸的计算

公式&#xff1a; 练习&#xff1a; 图1&#xff1a; input4&#xff0c;filter3&#xff0c;padding0&#xff0c;stride1 output2 图2&#xff1a; input5&#xff0c;filter3&#xff0c;padding0&#xff0c;stride2 output2 图3&#xff1a; input6&#xff0c;filter3&am…

设计模式之观察者模式、访问者模式与模板方法模式

目录 观察者模式 简介 优缺点 结构 实现 运用场景 访问者模式 简介 优缺点 结构 实现 运用场景 模板方法模式 简介 优缺点 结构 实现 运用场景 观察者模式 简介 又叫发布-订阅模式&#xff0c;定义对象间一种一对多的依赖关系&#xff0c;使得每当一个对象改…

Android 应用程序通过MediaPipe 图片识别

MediaPipe 中使用目标检测模型可以实现实时检测图像或视频中的物体&#xff0c;并标记出物体的位置和类别。MediaPipe 中的目标检测模型基于机器学习算法&#xff0c;经过训练以识别特定的物体类别&#xff1b; 以下是在 Android 应用程序中集成 MediaPipe Object Detection 的…