一位C++小白的力扣刷题_成长记录_欢迎 visit ^_^ ( 终于刷完初级啦~ 欧耶!)
数组_第1题:三数之和
题目描述:
给你一个包含 n 个整数的数组 nums
,判断 nums
中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
举例
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4], 满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]
解题思路: 先提示一点, “不包含重复的三元组” 的意思是,我举个栗子: 答案不能是 " [ -1,0,1 ] , [ -1,-1, 2 ] , [ -1 ,0 , 1 ] "。先排序,然后主要是解题工具就是——双指针。
其实有三个指针,习惯说成双指针。就是三个指针在 给定的数组上 移动。 符合要求则 放入 “vector容器”的一层。
学习心得:新学到sort()这个排序函数,可以减少我的记忆负担(即冒泡排序那些算法)。然后,主要一个难点
就是“去重”(即去掉重复的答案),这一点利用 指针的移动和continue的结合 得以解决。
实现:(C++)
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> v;
int size=nums.size();
int left,right,mid; //left:左指针。right:右指针。mid:中间指针
if( size<=2 ) return v; //特殊情况,特殊处理
sort( nums.begin(),nums.end() ); //①新学到 List库 里的 sort( 起始指向,终点指向 ) 函数
for( left=0;left<size;left++ )
{
if( left>0&&nums[left]==nums[left-1] ) //去重,也就是说,例如左指针只会在含有重复元素的 [ 1,2,2,2,-1 ] 中检索第一个2,后面的2都跳过
continue;
right=size-1;
for( mid=left+1;mid<size;mid++ )
{
if( mid>left+1&&nums[mid]==nums[mid-1] ) //保证中间指针在左指针的右边,并且 “ 去重 ”
continue;
while( mid<right&&nums[left]+nums[mid]+nums[right]>0 ) //保证中间指针在右指针的左边,并且调整 右指针
right--;
if( mid==right ) break; //如果 中间指针都和右指针重合了,说明 左指针和中间指针所加起来的数太小了,右指针指不到适合的数
if( nums[left]+nums[mid]+nums[right]==0 )
v.push_back( { nums[left],nums[mid],nums[right] } ); //②新学到一个 push_back() 的书写格式
}
}
return v;
}
};
运行结果:
我的输入
[-1,0,1,2,-1,-4]
我的答案
[[-1,-1,2],[-1,0,1]]
预期答案
[[-1,-1,2],[-1,0,1]]
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
数组_第2题:矩阵置零
题目描述:
给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法。
举例:
示例 1:
输入: [ [1,1,1], [1,0,1], [1,1,1] ] 输出: [ [1,0,1], [0,0,0], [1,0,1] ]
示例 2:
输入: [ [0,1,2,0], [3,4,5,2], [1,3,1,5] ] 输出: [ [0,0,0,0], [0,4,5,0], [0,3,1,0] ]
进阶:
- 一个直接的解决方案是使用 O(mn) 的额外空间,但这并不是一个好的解决方案。
- 一个简单的改进方案是使用 O(m + n) 的额外空间,但这仍然不是最好的解决方案。
- 你能想出一个常数空间的解决方案吗?
解题思路:我是想的是 先用一个队列来 储存矩阵里出现 “0” 的元素的下标。 记录完后 再在原矩阵上 “动手脚”。、
学习心得:这是一个笨方法,力扣上有更好的方法。但是这个方法是我自己想出来的,也独立完成了,
还是有点小开心,哈哈哈~ 待我第二遍刷到你时,再来切磋切磋!
实现:(C++)
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int row_size=matrix.size(); //row_size 用来储存matrix行的个数
int col_size=matrix[0].size(); //col_size 用来储存matrix每行中的元素的个数
int row,col;
queue<int> q; //一号小分队出来!
int i,j;
for( i=0;i<row_size;i++ )
for( j=0;j<col_size;j++ )
if( matrix[i][j]==0 ) //记录那些 背上含有“0”的 “间谍”
{
q.push( i );
q.push( j );
}
for( i=0;!q.empty(); ) //只要队列不为空,说明还有 “间谍” 未被清除
{
row=q.front();
q.pop();
matrix[ row ].assign( col_size,0 ); //③新学到一个 vector库里的 assign( 坐标, 赋给那个坐标的值 )函数
col=q.front();
for( j=0;j<row_size;j++ )
matrix[ j ][ col ]=0;
q.pop(); //注意:“间谍”有横坐标和纵坐标,所以要pop()两次
}
}
};
运行结果:
代码执行结果:
我的输入
[[1,1,1],[1,0,1],[1,1,1]]
我的答案
[[1,0,1],[0,0,0],[1,0,1]]
预期答案
[[1,0,1],[0,0,0],[1,0,1]]
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
数组_第3题:字母异位词分组
题目描述:
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
举例:
示例:
输入: ["eat", "tea", "tan", "ate", "nat", "bat"]
输出:
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
说明:
- 所有输入均为小写字母。
- 不考虑答案输出的顺序。
解题思路:灵活运用 哈希表(无序)。然后结合 sort() 函数,整理每个字符串,整理过后的 字母异位词 是相同的结果,然后他们就可以放入 同一个 键值对里面。
到最后 一排排 地输出。
学习心得:做了这道题,我又对这个哈希表啊,既爱又恨,爱是其功能强大,适合这道题,恨是很多
关于maps的格式、库函数不了解,屡屡碰壁。
实现:(C++)
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string,vector<string>> hashmap; //构造一个 无序哈希表(unordered_map),key(键)对应string类型,val(值)对应vector属性的 string类型
vector<vector<string>> v_res;
string temp; //temp是个打工仔,做做替身
int index=0;
for( auto s:strs )
{
temp=s;
sort( temp.begin(),temp.end() ); //整理“打工仔”,例如:"eta"整理后为“aet”;“dcba”整理后为“abcd”
hashmap[ temp ].push_back( s ); //如果哈希表中无“aet”这个key(键),则自动新建一个key(键)。并将未被“sort()”的字符串s放入
}
v_res.resize( hashmap.size() ); //④自学了 vector库里的resize( 整数数值 )函数
for( auto it:hashmap ) //⑤原来auto还可以这样用,长知识了!
{
v_res[ index ]=it.second ; //it是个迭代器。 类似于 C++ 中的对象(具有一些公有成员/共有成员函数)。it.second访问的it指向的val(值)
index++;
}
return v_res;
}
};
运行结果:
代码执行结果:
我的输入
["eat","tea","tan","ate","nat","bat"]
我的答案
[["bat"],["eat","tea","ate"],["tan","nat"]]
预期答案
[["bat"],["nat","tan"],["ate","eat","tea"]]
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
数学_第4题: 无重复字符的最长子串
题目描述:
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
举例:
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其
长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b"
,所以其长度为 1。
示例 3:
输入: "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是"wke"
,所以其长度为 3。 请注意,你的答案必须是 子串 的长度,"pwke"
是一个子序列,不是子串。
解题思路:双指针,再一次登场!再结合标准关联容器set (系统能根据元素的值自动进行排序)来解题。
学习心得:今天第二次使用“双指针”,又是针对于 解决字符串 这样的题。然后今天学习到了 C++中set 这个库。
在力扣 的官方解题思路中,提到“滑动窗口”,这个名词形容得很恰当。
实现:(C++)
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_set<char> js;
int n=s.size();
int left,right=-1,res=0; //left:左指针。right:右指针(至于为什么要赋初始值为 -1 ,是因为用于表示 s[ right+1 ] )
//其实刚开始我是不知道right应该赋什么初始值的,但是敲到后面,就发现赋值-1 更方便
for( left=0;left<s.size();left++ )
{
if( left!=0 ) //如果left,即左指针下标值不为零,清除 前一位 的值。(只是清除,但那个位置依然保留)
js.erase( s[left-1] ); //⑥新学到 set标准库 里的 erase( 数据 )函数。
while( right<n-1&&!js.count( s[right+1] ) ) //⑦新学到 set标准库 里的 count( 数据 )函数。作用是:返回 set属性的对象中 某个值元素的个数
//提醒一下,n不能换成s.size()。我现在还不知道为什么
{
js.insert( s[right+1] ); //⑧新学到 set标准库 里的 insert( 数据 )函数。作用:在集合中插入元素
right++; //插入一个元素后,右指针继续向右移动,循环,再判断
}
res=max( right-left+1,res ); //“ right-left+1 ” 是敲到后面,自然而然想到的
}
return res;
}
};
运行结果:
我的输入
"abcabcbb"
我的答案
3
预期答案
3