| Severus-Yuan的专栏 | 链接🔗 |
|---|---|
| C语言 | C语言 |
| 初阶数据结构与算法 | 初阶数据结构与算法 |
| 数据结构算法题 | 数据结构算法题 |
| C++ | C++ |
文章目录
- 1.只出现一次的数字I
- 题解:
- 2.只出现一次的数字II
- 题解
- 3.只出现一次的数字III
- 题解:
- 4.杨辉三角
- 题解:
- 5.删除有序数组中的重复项
- 题解:
- 6.数组中出现次数超过一半的数字
- 题解:
- 7.电话号码的字母组合
1.只出现一次的数字I
只出现一次的数字I
题解:
//比较简单,走单身狗异或那一套就行,只是从数组换成了顺序表classSolution{public:intsingleNumber(vector<int>&nums){intsum=nums[0];for(size_t i=1;i<nums.size();i++){sum^=nums[i];}returnsum;}};2.只出现一次的数字II
只出现一次的数字II
题解
classSolution{public:intsingleNumber(vector<int>&nums){intans=0;for(inti=0;i<32;++i){// 统计该每个数字第i个比特位为1的总数// int四字节 32比特位inttotal=0;for(intnum:nums){total+=((num>>i)&1);}// 如果total能够被3整除,说明只出现一次的数字在该位置上一定是0// 否则在该位置上一定是1if(total%3){ans|=(1<<i);}}returnans;}};我们来分析一下代码的每一步的逻辑:
首先先看清题目,题目中说数组中的元素要么是三个三个相同出现,要么是单个单个出现,针对题目所给的前提,则在相同比特位上相加的结果只有0/1/4三种可能(即都是0,或只有单个元素为1三个相同元素为0,或单个和三个相同元素都为1)。那么%3也就只有两种情况,0或者1。题目的目的是要找到落单的元素,而题解的逻辑是通过还原落单元素的补码来找落单元素,通过确定落单元素补码的每一位是0还是1来找落单元素。%3的逻辑是去除三个相同元素在该比特位上为1的情况。ans就是我们定义的一个,用来记录找到落单元素补码的每一个比特位的变量。
外层for循环:由于int是4字节32比特位,所以循环是32轮;
内层循环的目的是统计数组中所有元素在这32个比特位的和,total就是记录和的变量。num >> i移位可以将元素的i位上的比特位移到最右边,&1后就能得到元素的i为的比特位的值(1的补码是00000000000000000000000000000001,前面31都为0,最后1位取决于元素的i位上是1还是0),内层循环结束后,数组所有元素在i位上比特位的和就得出来了。
if语句的目的是修改ans的补码的比特位(记录落单元素补码的每一个比特位),如果total%3= =0,则说明落单元素补码的i位上就是0,如果total%3= =1,则说明落单元素补码的i位上就是1,就需要进行修正。|的运算法则是只要有1就是1,全0才是0。所以ans|((1 << i))不会改变ans原先已有的1,只会当原先是0的位置遇上i中是1的位置变成1,而这个变成1的过程,也就是进入if语句进行修正的目的。记住一定是|=,因为ans是实时更新的。
(合理怀疑,这种方法放平时根本想不到。。。。。。)
3.只出现一次的数字III
只出现一次的数字III
题解:
//法1:排序法classSolution{public:vector<int>singleNumber(vector<int>&nums){//排序sort(nums.begin(),nums.end());//返回的数组不属于额外空间vector<int>res;for(inti=0;;i<nums.size()-1;i++)//nums.size()-1是为了考虑nums[i + 1]{if(nums[i]==nums[i+1]){i+=2;//出现前后相等,就跳过这两个元素}else{res.push_back(nums[i]);i+=1;}}if(i<nums.size()){res.push_back(nums[i]);}returnres;}};//法二:classSolution{public:vector<int>singleNumber(vector<int>&nums){longs=0;//当数组中出现-2^32时,-s=2^32,超出了int的存储范围,所以类型换成longfor(autox:nums){s^=x;}intlowbit=s&-s;//-s保留二进制最右边的1//逻辑与之后除最右边的1位置为1,其余位置均为0——>得到最右边1的位置inta=0,b=0;//题目限定只有两个仅出现一次的元素for(autox:nums){//if((x & lowbit) == lowbit)if(x&lowbit)//只有当对应lowbit位置二进制数字为1,才会在该位逻辑与成1//否则该位为0且全部位都为0{a^=x;}else{b^=x;}}returnvector<int>{a,b};}};法二的方法有一丝曲折,我们来好好分析一下:
4.杨辉三角
杨辉三角
题解:
classSolution{public:vector<vector<int>>generate(intnumRows){vector<vector<int>>v(numRows);for(inti=0;i<numRows;i++){vector<int>v1(i+1,1);v[i]=v1;//创建新vector<int>之后进行尾插}for(inti=2;i<numRows;i++){for(intj=1;j<v[i].size()-1;j++){v[i][j]=v[i-1][j-1]+v[i-1][j];}}returnv;}};classSolution{public:vector<vector<int>>generate(intnumRows){vector<vector<int>>vv(numRows);for(inti=0;i<numRows;++i){vv[i].resize(i+1,1);//调整已有的vector<vector<int>>中每一行vector<int>的容量大小}for(inti=2;i<numRows;++i){for(intj=1;j<i;++j){vv[i][j]=vv[i-1][j]+vv[i-1][j-1];}}returnvv;}};自我感觉思路比较顺畅,此处不多赘述。
相比于用C++解这道题,C语言就要复杂得多,像此类要返回数组的题目,同时也要求返回数组的长度(一维数组返回长度,二维数组就要返回行数和列数)。由于杨辉三角的二维数组的行数不定且每一行的列数都不一样,所以只能动态开辟。需要返回二维数组的行数和列数,行数好说,但每一行的列数都是不同的,所以需要动态开辟一个数组用于存储了每一行的列数,想要在函数外部访问一维数组,那就要拿到一维数组指针的指针,即二级指针。
5.删除有序数组中的重复项
删除有序数组中的重复项
题解:
classSolution{public:intremoveDuplicates(vector<int>&nums){for(inti=0;i<nums.size()-1;i++){if(nums[i]==nums[i+1]){nums.erase(nums.begin()+i+1);//以防出现多个等值的情况,故而删除之后保留原先的i再进行判断i--;}}returnnums.size();}};6.数组中出现次数超过一半的数字
数组中出现次数超过一半的数字
题解:
classSolution{public:/** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * @param numbers int整型vector * @return int整型 */intMoreThanHalfNum_Solution(vector<int>&numbers){//单独处理数组元素为1的情况if(numbers.size()==1){returnnumbers[0];}//排序sort(numbers.begin(),numbers.end());intcount=0;for(inti=0;i<numbers.size()-1;i++){inttmp=i;//这里是while循环,不能用if选择while(numbers[i]==numbers[i+1]){count++;i++;}//必须写>=,>是错的//因为是前后相等count自增一次,那么相同的数出现5次但count只记录了4次(4次前后相等)if(count>=numbers.size()/2){returnnumbers[i];}count=0;i=tmp;}return0;}};7.电话号码的字母组合
电话号码的字母组合
第七题的知识点涉及哈希表,我暂时还没学,先不讲。(2026.11.5)
——end——