【vector题解】杨辉三角 | 删除有序数组中的重复项 | 只出现一次的数字Ⅱ

news2024/11/20 13:42:41

杨辉三角

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

给定一个非负整数 numRows生成「杨辉三角」的前 numRows 行。

在「杨辉三角」中,每个数是它左上方和右上方的数的和。

示例 1:

输入: numRows = 5
输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]

示例 2:

输入: numRows = 1
输出: [[1]]

知识点

这道题涉及的知识点有:1. vector创建二维数组。 2. 杨辉三角的表示法。

vector如何创建数组?

创建一维数组的方法:

vector<int> v(5);  //创建5个int,初始化成默认值0
​
vector<int> v(5,1);  //创建5个int,初始化成1
​
vector<int> v={1,2,3};  //创建3个int,分别是1,2,3

创建二维数组的方法:

vector<vector<int>>(5);    //创建5行。 若想要定义列的大小,用resize()
​
vector<vector<int>>(5,vector<int>(4));   //创建5行4列,初始化成默认值0
​
vector<vector<int>>(5,vector<int>(4,9));  //创建5行4列,初始化成默认值9

这道题的二维数组,每行的大小都不一样的:

大小我们用resize()去调整。

至于杨辉三角的表示法,它的规律是:每行的开头和末尾为1,其他的数之间的关系 用找规律法可以得出:v[i] [j]=v[i-1] [j-1] + v[i-1] [j]

解答

class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        vector<vector<int>> v(numRows); 
        for(int i=0;i<numRows;i++){
            v[i].resize(i+1);
            v[i][0]=v[i][i]=1;
            for(int j=1;j<i;j++){
                    v[i][j]=v[i-1][j-1]+v[i-1][j];
                }
        }
        return v;
    }
};

删除有序数组中的重复项

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。

  • 返回 k

示例 1:

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例 2:

输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

思路与实现

这道题我想到了两个思路。

思路一:

设两个迭代器:fast、slow。它们初始都指向nums的第一个元素。

fast一步一步地持续往前走,slow暂时待在原地。每当fast指向的元素和slow指向的不一样,就让slow加加,把fast的值赋给slow。

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        vector<int>::iterator fast=nums.begin(),slow=nums.begin();
        while(fast!=nums.end()){
            if(*fast!=*slow){
                slow++;
                *slow=*fast;
            }
            fast++;
        }
        int k=slow-nums.begin()+1;
        nums.resize(k);
        
        return k;
    }
};

思路二:

把数组遍历一遍,遇到和上一个相同的就删除。

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        vector<int>::iterator it=nums.begin();
        while(it!=nums.end()){
            if(it+1!=nums.end()){   //小心越界,加个判断
                if(*it==*(it+1)){
                it=nums.erase(it);
                }
                else{
                    it++;
                }
            }
            else{
                it++;
            }
        }
        int k=nums.size();
        return k;
    }
};

这个思路二挺容易写错的,看看我之前的错误写法:

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        vector<int>::iterator it=nums.begin();
        while(it!=nums.end()){
            if(it+1!=nums.end()){
                if(*it==*(it+1)){   //如果it没走这里的if条件,那它也没法自增,程序就陷入死循环了
                it=nums.erase(it);
                }
            }
            else{
                it++;
            }
        }
        int k=nums.size();
        return k;
    }
};

这样写的问题,还是出在erase那边。之前我强调过,erase因为会引起迭代器失效,所以写法非常讲究。

正确的erase写法:

要用if else语句,并且要用迭代器去承接erase的返回值。

而这里,我只写了if,漏写了else。在else里,it要加加。

错误记录

这样写,为什么报错呢?

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int sz=nums.size();
        int i=0;
        while(i<sz){
            if(i>0){
                if(nums[i]==nums[i-1]){
                    vector<int>::iterator pos=nums.begin()+i;
                    pos=nums.erase(pos);   //这里要考虑迭代器失效吗?
                }
                else{
                    i++;
                }
            }
            else{
                i++;
            }   
        }
        int k=nums.size();
        return k;
    }
};

原来,是因为我循环里的erase操作,会导致size()被修改,sz的值失效了。

只出现一次的数字Ⅱ

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。

示例 1:

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

示例 2:

输入:nums = [0,1,0,1,0,1,99]
输出:99

思路

这道题乍一看,长得像单身狗问题,但实际并不能用异或的方法去做,两个相同的值异或在一起为0,而这里是三个相同的值。

思路一:先排序,再前后比较

这题其实可以借鉴刚刚那道“删除数组中的重复项”,把乱序的数组排序,使得大小相同的数字紧挨在一起,当一个数和前后都不相同,那这个数就只出现了一次。

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int sz=nums.size();
        //首先要考虑特殊情况
        if(sz==1){
            return nums[0];
        }
        sort(nums.begin(),nums.end());
        for(int i=0;i<sz;i++){
            //先考虑第一个和最后一个,这俩位置比较尴尬,容易越界访问
            if(i==0&&nums[i]!=nums[i+1]){
                return nums[i];
            }
            else if(i==sz-1&&nums[i]!=nums[i-1]){
                return nums[i];
            }
            else if(nums[i]!=nums[i+1]
                &&nums[i]!=nums[i-1]){
                return nums[i];
            }
        }
        return 0;
    }
};

思路二:位运算

先撇开那个只出现一次的数字不看(我们就叫它A),其他数字都是三个三个出现的。

此时将十进制的数字用二进制的视角来看的话,32个比特位,1出现的次数一定是3的倍数。

而加进来A以后,我们将目光投到任意一个比特位上。如果A的这个比特位是0,那1的次数依然是3的倍数;如果是1,那这个次数模3等于1。

也就是说,我们可以通过1的次数 倒推出A的 其中一个比特位了:设1出现x次,x%3==0,那A的这一位就是0;x%3 ==1,这一位就是1。

A一共有32个比特位,复刻这个方法,可以推出A的每一个比特位,A的值自然也就出来了。

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        //一共32个比特位,每一位的0、1值我们都要获知
        int ret=0;
        for(int i=0;i<32;i++){
            //统计1出现的次数n
            int n=0;
            for(int num:nums){
                if((num>>i)&1==1){
                    n++;
                }
            }
            if(n%3==1){
                ret|=1<<i;   //注意:二进制的加法就用|
            }            //刚刚右移了i位,现在再左移回来
        }
        return ret;
    }
};

小结

1.“去重”问题往往可以考虑先排个序。

2.按位或 相当于是二进制中的加法。

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

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

相关文章

操作系统【OS】死锁

常考点 系统资源不足不是系统产生死锁的原因&#xff0c;资源不足只会对进程造成“饥饿”【详见王道操作系统书P153第4题】 A&#xff1a;资源不足和资源分配不足还是有区别的啦~ 死锁是什么&#xff1f; 死锁是多个进程因为竞争资源而造成的一种互相等待 为什么会出现死锁&…

软考系统架构师知识点集锦二:软件工程

一、考情分析 二、考点精讲 2.1 软件过程模型 &#xff08;1&#xff09;原型模型 典型的原型开发方法模型。适用于需求不明确的场景,可以帮助用户明确需求。可以分为[抛弃型原型]与[演化型原型] 原型模型两个阶段: 1、原型开发阶段;2、目标软件开发阶段。 &#x…

Unity报错:Microsoft Visual C# Compiler version

Unity报错:Microsoft Visual C# Compiler version 问题解决方案总结 问题 Microsoft Visual C# Compiler version 2.9.1.65535 (9d34608e) Copyright © Microsoft Corporation 切换版本或者使用老项目的时候可能会出现这个报错&#xff0c;这个报错就是项目设置的问题 …

计算机起源(三)

一、前言 计算机在完成了硬件和操作系统的构建后&#xff0c;最重要的一件事情就是要处理数据。在现代意义的数据库出现之前(20世纪60年代)&#xff0c;人们通过人工和文件系统的方式来存储、管理数据。在人工管理时期&#xff0c;人们常使用穿孔纸带来管理数据 &#xff0c;虽…

华为机试题:HJ4 字符串分隔

目录 第一章、算法题1.1&#xff09;题目描述1.2&#xff09;解题思路与答案1.3&#xff09;牛客链接 友情提醒: 先看文章目录&#xff0c;大致了解文章知识点结构&#xff0c;点击文章目录可直接跳转到文章指定位置。 第一章、算法题 1.1&#xff09;题目描述 题目描述&…

前端html+css+js实现的2048小游戏,很完善。

源码下载地址 支持&#xff1a;远程部署/安装/调试、讲解、二次开发/修改/定制 逻辑用的是JavaScript&#xff0c;界面用canvas实现&#xff0c;暂时还没有添加动画。 视频浏览地址

mac安装并使用wireshark

mac安装并使用wireshark 1 介绍 我们在日常开发过程中&#xff0c;遇到了棘手的问题时&#xff0c;免不了查看具体网络请求情况&#xff0c;这个时候就需要用到抓包工具。比较著名的抓包工具就属&#xff1a;wireshark、fildder。我这里主要介绍wireshark。 2 安装 以mac安装为…

电压放大电路适用于什么场合(电压放大器)

电压放大电路是一种常见的电子电路&#xff0c;可将输入信号的电压放大到更高的水平&#xff0c;从而提高信号的强度和可靠性。它在各个领域都有广泛的应用&#xff0c;下面将介绍电压放大电路的适用场合。 电压放大电路广泛应用于音频领域。音频信号的传输和处理需要较高的电压…

你真的了解CPU和GPU?

目录 先举个栗子 CPU 什么是CPU CPU的定义 CPU的组成 CPU的功能 GPU 什么是GPU GPU的定义 GPU的组成 GPU的功能 CPU和GPU的区别 先举个栗子 假设你正在编辑一份文档&#xff0c;这时可以将CPU和GPU的角色比喻为文档编辑过程中的两个不同任务。 1. CPU CPU就好比是…

自动驾驶之—LaneAF学习相关总结

0.前言&#xff1a; 最近在学习自动驾驶方向的东西&#xff0c;简单整理一些学习笔记&#xff0c;学习过程中发现宝藏up 手写AI 1. 概述 Laneaf思想是把后处理放在模型里面。重点在于理解vaf&#xff0c; haf&#xff0c;就是横向聚类&#xff1a;中心点&#xff0c;纵向聚类&…

C语言之预处理

目录 前言 宏定义define的用法 文件包含include的用法 条件编译的用法 其他预处理命令 练习题 练习一 练习二 练习三 前言 预处理命令可以改变程序设计环境&#xff0c;提高编程效率&#xff0c;它们并不是C语言本身的组成部分&#xff0c;不能直接对它们进行编译&am…

竹云产品入选《2023年度上海市网络安全产业创新攻关成果目录》

为推进网络安全产业发展&#xff0c;建设网络安全产业创新高地&#xff0c;上海市经济和信息化委员会于10月24日正式发布《2023年度上海市网络安全产业创新攻关成果目录》&#xff0c;共评选出16项创新成果&#xff0c;其中包括基础技术创新8项、应用技术创新4项、服务业态创新…

源码推荐【源码好优多】

一、影视小程序 特点&#xff1a;可独立部署、消耗环境小、安全可靠。使用微信小程序技术开发。部署简单容易。该项目的部署需要具备微擎框架的开发以及部署能力 二、java博客管理系统 博客管理系统是一个融合线上、线下的网民在线交流管理信息化系统。它的使用为网民、运营者搭…

FineReport模版报错排查

在【智能运维——》平台日志——》模版报错】目录下可以查看在使用中有报错的模版&#xff0c;可在【下载日志】目录下下载具体时间断的日志进行报错分析。 常见报错 1、 11300003&#xff1a;com.fr.stable.DeathCycleException: pInvCode_sn 出现原因&#xff1a; 模版参数…

Linux 云服务器磁盘挂载简介

云服务器磁盘挂载 一、挂载须知 一般涉及工具或命令&#xff1a;fdisk/gdisk/parted等挂载&#xff08;mounting&#xff09;是指由操作系统使一个存储设备&#xff08;诸如硬盘、CD-ROM或共享资源共享资源上的计算机文件和目录可供用户通过计算机的文件系统访问的一个过程。…

Linux ls命令:查看目录下文件

ls 命令&#xff0c;list 的缩写&#xff0c;是最常见的目录操作命令&#xff0c;其主要功能是显示当前目录下的内容。此命令的基本格式为&#xff1a; [rootlocalhost ~]# ls [选项] 目录名称 ls 命令常用的选项以及各自的功能。 注意&#xff0c;当 ls 命令不使用任何选项时…

基于arduino uno + L298 的直流电机驱动proteus仿真设计

一、L298简介&#xff1a; L298是一个集成的单片电路&#xff0c;采用15个导线多瓦和PowerSO20封装。它是一个高电压、高电流双全桥驱动器&#xff0c;旨在接受标准TTL逻辑电平和驱动感应负载&#xff0c;如继电器、螺线管、直流和加速电机。提供两个使输入来使独立于输入信号的…

Vue---监听div元素宽高改变时echart图表重新resize

一、需求描述 当点击上图的红色框时&#xff0c;echart的div元素宽会改变但是无法触发echarts图表的resize重新渲染&#xff0c;对于浏览器而言&#xff0c;浏览器具有window.resize方法监听浏览器窗口大小的改变&#xff0c;而div元素没有监听宽高改变的方法。 二、解决方案 …

STM TIM(三) 输入捕获

STM TIM(三) 输入捕获 输入捕获简介 IC&#xff08;Input Capture&#xff09;输入捕获 输入捕获模式下&#xff0c;当通道输入引脚出现指定电平跳变时&#xff08;上升沿或下降沿&#xff09;&#xff0c;当前CNT的值将被锁存到CCR中&#xff08;把当前CNT的值读出来&#x…