今天写了两道力扣练习题,难度:★★~★★★,每道题都写了不止一种写法,也有官方题解,本来以为今天只能写一道题的,超额完成了✌。
一.比较含退格的字符串 ★★★☆☆
题目
力扣844.给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。注意:如果对空文本输入退格字符,文本继续为空。
我的思路
1.利用双指针实现元素的判断和赋值:fast指针负责遍历字符串s和t;slow指针负责作为动态指针sArr和tArr的索引。针对不同的情况,对fast和slow进行更新
2.更新元素:当s[fast] != '#' 时,直接将s[fast]赋值给sArr[slow],并且将fast和slow都向后移动;当s[fast] == '#' 时,slow向前移动,以便fast碰到下一个不是#的元素,进行赋值操作,相当于覆盖。
3.对s和t分开操作,然后用strcmp(sArr和tArr)和0比较,将比较结果赋值给bool变量res,最后返回res即可。
遇到过的报错+分析说明:
1.heap-buffer-overflow,由写操作越界引起 (向动态分配的数组进行写入操作时,访问了数组范围外的地址):如果用 char* tArr=(char*)malloc((tLen)*sizeof(char)); 语句动态分配,当字符串为空字符串时,不会分配空间,而最后还有tArr[slow]='\0';语句进行赋值操作,就会报错。
2.stack-buffer-overflow(栈缓冲区溢出),由字符串索引越界引起:因为最的思路是用 i 控制次数,而没有直接用fast,所以没有对fast进行范围的限制,导致fast大于了数组的范围。
cpp
int fast=0;
int slow=0;
for(int i=0;i<sLen;i++){
while(s[fast]=='#'){
fast++;
if(slow!=0){
sArr[--slow]=0;
}
}
sArr[slow++]=s[fast++];
}
下面有两个代码,核心区别只有一处,但是运行结果是有差异的
代码1
cpp
class Solution {
public:
bool backspaceCompare(string s, string t) {
int sLen=s.size();
int tLen=t.size();
//预留一个空间存'\0'
char* sArr=(char*)malloc((sLen+1)*sizeof(char));
char* tArr=(char*)malloc((tLen+1)*sizeof(char));
if(sArr==NULL || tArr==NULL){
free(sArr);
free(tArr);
return false;
}
//---------------------------
int slow=0;
int fast=0;
for(;fast<sLen;fast++){
if(s[fast]=='#'){
if(slow>0){
slow--;
}
}
else{
sArr[slow++]=s[fast];
}
}
sArr[slow]='\0';
slow=0;
for(fast=0;fast<tLen;fast++){
if(t[fast]=='#'){
if(slow>0){
slow--;
}
}
else{
tArr[slow++]=t[fast];
}
}
tArr[slow]='\0';
bool res=(strcmp(sArr,tArr)==0);
free(sArr);
free(tArr);
return res;
}
};
代码2
cpp
class Solution {
public:
bool backspaceCompare(string s, string t) {
int sLen=s.size();
int tLen=t.size();
//预留一个空间存'\0'
char* sArr=(char*)malloc((sLen+1)*sizeof(char));
char* tArr=(char*)malloc((tLen+1)*sizeof(char));
//---------------------------
int slow=0;
int fast=0;
for(;fast<sLen;fast++){
if(s[fast]=='#'){
if(slow>0){
slow--;
}
}
else{
sArr[slow++]=s[fast];
}
}
sArr[slow]='\0';
slow=0;
for(fast=0;fast<tLen;fast++){
if(t[fast]=='#'){
if(slow>0){
slow--;
}
}
else{
tArr[slow++]=t[fast];
}
}
tArr[slow]='\0';
bool res=(strcmp(sArr,tArr)==0);
free(sArr);
free(tArr);
return res;
}
};
核心区别:是否在分配空间后进行NULL的判断和处理


消耗内存分布的差异主要是一些极端场景的例子造成的。第一个代码有对NULL的处理,面对极端情况就不会往后继续执行,减少了后续各种内存的消耗。
力扣官方题解
题解1
模拟"栈"的操作:遍历字符串的每一个字符,遇到非#,将其"入栈",加入res中;遇到#,将res"栈顶"的元素弹出(在res非空时才能弹出)
说明:for(char ch : s){ } 相当于 for(int i=0;i<s.size();i++) { char ch=s[i]; }
cpp
class Solution {
public:
bool backspaceCompare(string s, string t) {
return build(s)==build(t);
}
string build(string s){
string res;
for(char ch:s){
if(ch=='#'){
if(!res.empty()){
res.pop_back;
}
}else {
res.push_back(ch);
}
}
return res;
}
};

题解2
双指针(有一点点难理解,我下次理解了再来写下我的理解)
cpp
class Solution {
public:
bool backspaceCompare(string S, string T) {
int i = S.length() - 1, j = T.length() - 1;
int skipS = 0, skipT = 0;
while (i >= 0 || j >= 0) {
while (i >= 0) {
if (S[i] == '#') {
skipS++, i--;
} else if (skipS > 0) {
skipS--, i--;
} else {
break;
}
}
while (j >= 0) {
if (T[j] == '#') {
skipT++, j--;
} else if (skipT > 0) {
skipT--, j--;
} else {
break;
}
}
if (i >= 0 && j >= 0) {
if (S[i] != T[j]) {
return false;
}
} else {
if (i >= 0 || j >= 0) {
return false;
}
}
i--, j--;
}
return true;
}
};
。
二.有序数组的平方 ★★☆☆☆
题目
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
思路1------暴力法
直接计算出nums中每个数的平方,并保存在新数组中,然后利用sort函数对新数组进行升序排序
代码
cpp
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int len=nums.size();
vector<int> res(len);
for(int i=0;i<len;i++){
res[i]=nums[i]*nums[i];
}
sort(res.begin(),res.end());
return res;
}
};
思路2------"双指针"法
这里的双指针我打了双引号,因为感觉跟题解的双指针相比还是low low的
我的思路是找出nums中的第一个正数的位置 i,将left和right两个指针分别设为 i - 1 和 i,然后通过比较两个指针的值将较小的放入新数组中(index作为新数组的索引,从0开始往后移动)
如果只是找第一个正数的位置,就无法处理全为负数的情况,所以我添加了标志变量flag,作为nums数组中是否有正数/0的标志,如果有就置flag=1。遍历完nums后,如果flag为0,直接从数组长度的一半处规定两个指针,但是left=len-1; right=len。可以通过全是正数的情况理解:全是正数,nums数组本身就是从小到大排序,所以置left=-1; right=0; 而left<0,不会进入while循环,直接进行后续的操作(对right进行移动);nums数组全为负数的情况类似,令left=len-1; right=len; 将left一直向前移动即可
我的思路有一点麻烦,可以选择看后面的官方题解思路
代码1
cpp
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int len=nums.size();
vector<int> res(len);
//以第一个正数作为分界点,两个指针分别向两边移动
//比较两个指针所指的数的平方,小的放入res然后移动
int index=0;//res的索引
int left=0;
int right=0;
int flag=0;
//遍历nums找到第一个正数
for(int i=0;i<len;i++){
if(nums[i]>=0){
left=i-1;
right=i;
flag=1;
break;
}
}
if(flag==0){
left=len-1;
right=len;
}
while(right<len && left>=0){
if(nums[left]*nums[left]<=nums[right]*nums[right]){
res[index++]=nums[left]*nums[left];
left--;
}else{
res[index++]=nums[right]*nums[right];
right++;
}
}
//处理剩余数字
//右边没走完
if(right<len){
while(right<len&&index<len){
res[index++]=nums[right]*nums[right];
right++;
}
}else{
while(left>=0){
res[index++]=nums[left]*nums[left];
left--;
}
}
return res;
}
};
代码2
将只有正负数的情况单独提取出来了,直接利用for循环对新数组的元素进行赋值
cpp
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int len=nums.size();
vector<int> res(len);
//只有正数
if(nums[0]>=0){
for(int i=0;i<len;i++){
res[i]=nums[i]*nums[i];
}
return res;
}
//只有负数
else if(nums[len-1]<=0){
for(int i=0,j=len-1;i<len;i++,j--){
res[j]=nums[i]*nums[i];
}
return res;
}
//正负数都有
else{
//以第一个正数作为分界点,两个指针分别向两边移动
//比较两个指针所指的数的平方,小的放入res然后移动
int index=0;//res的索引
int left=0;
int right=0;
int flag=0;
//遍历nums找到第一个正数----------------无法处理全负数的情况
for(int i=0;i<len;i++){
if(nums[i]>=0){
left=i-1;
right=i;
break;
}
}
while(right<len && left>=0){
if(nums[left]*nums[left]<=nums[right]*nums[right]){
res[index++]=nums[left]*nums[left];
left--;
}else{
res[index++]=nums[right]*nums[right];
right++;
}
}
//处理剩余数字
//右边没走完
if(right<len){
while(right<len&&index<len){
res[index++]=nums[right]*nums[right];
right++;
}
}else{
while(left>=0){
res[index++]=nums[left]*nums[left];
left--;
}
}
return res;
}
}
};
力扣官方题解
代码1
利用双指针,i 从前往后,j 从后往前,比较两个指针指向的元素的值,比较大小,对新数组元素赋值。将指向较大的元素的指针在赋值后进行移动,比较下一个元素。
无论是只有正/负数,还是一般的正负数都有的情况,都可以通过先找出最大值来对新数组元素赋值,所以新数组索引初始化为len-1,然后往前移动。
循环结束条件是 i<=j ,而不是 i<j,因为存在 i 和 j 相等的情况
cpp
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int len=nums.size();
vector<int> res(len);
for(int i=0,j=len-1,index=len-1;i<=j;){//循环结束条件:i<=j
if(nums[i]*nums[i]>nums[j]*nums[j]){
res[index--]=nums[i]*nums[i];
i++;
}else{
res[index--]=nums[j]*nums[j];
j--;
}
}
return res;
}
};
代码2
理解困难+1
cpp
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int n = nums.size();
int negative = -1;
for (int i = 0; i < n; ++i) {
if (nums[i] < 0) {
negative = i;
} else {
break;
}
}
vector<int> ans;
int i = negative, j = negative + 1;
while (i >= 0 || j < n) {
if (i < 0) {
ans.push_back(nums[j] * nums[j]);
++j;
}
else if (j == n) {
ans.push_back(nums[i] * nums[i]);
--i;
}
else if (nums[i] * nums[i] < nums[j] * nums[j]) {
ans.push_back(nums[i] * nums[i]);
--i;
}
else {
ans.push_back(nums[j] * nums[j]);
++j;
}
}
return ans;
}
};