1.82. 删除排序链表中的重复元素 II
题目描述:
给定一个已排序的链表的头 head
, 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。
示例:
解答描述:
删除有序链表中的重复数字的解题思路不难,就是从头开始遍历,跳过所有的重复数字即可。
该题难点在于链表的实现上,因为要返回头结点,而头结点head可能会被删除,所以需要开辟一个新的哑结点new_head,new_head->next=head,最终只需要返回new_head->next即可。
用两个指针r=new_head,p=head,前后遍历。
代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(head==NULL || head->next==NULL)//只有0个或1个元素,直接返回即可
{
return head;
}
ListNode *p=head;
ListNode *new_head=new ListNode();//新的负责节点,哑结点,它的后面是head节点
new_head->next=head;
ListNode *r=new_head;
while(p!=NULL)
{
while(p->next!=NULL && p->next->val==p->val )//有重复时,把所有重复的删除
{
p=p->next;
}
if(r->next==p)//r和p直接没有其他元素时,直接令r=r->next
{
r=r->next;
}
else//不存在重复的该元素,直接加入结果链表
{
r->next=p->next;
}
p=p->next;
}
return new_head->next;
}
};
2.15. 三数之和
题目描述:
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = []
输出:[]
示例 3:
输入:nums = [0]
输出:[]
解答描述:
这是第二次做这个题了,思路也很简单,固定a,双指针扫描b,c。
关键点在于为了得到不重复的三元组,需要对a,b,c都跳过重复的字符。
代码:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n=nums.size();
vector<vector<int>> ans;
vector<int> temp(3);
//先排序
sort(nums.begin(),nums.end());
//然后枚举每个a,双指针法找到相应的b,c
for(int i=0;i<n-2;i++)
{
if(nums[i]>0)
{
return ans;
}
if(i>0 && nums[i]==nums[i-1])//对a去重
{
continue;
}
int l=i+1;
int r=n-1;
while(l<r)
{
if((nums[i]+nums[l]+nums[r])==0)
{
temp[0]=nums[i];
temp[1]=nums[l];
temp[2]=nums[r];
ans.emplace_back(temp);
//关键一步,去除重复的b和c
/*//为什么这样就超出时间限制
while(l<r && nums[l]==nums[l+1]){l=l+1;}
while(l<r && nums[r]==nums[r-1]){r=r-1;}*/
//为什么这样又可以呢
while(l<r && nums[l]==nums[++l]);
while(l<r && nums[r]==nums[--r]);
}
else if((nums[i]+nums[l]+nums[r])>0)
{
r--;
}
else
{
l++;
}
}
}
return ans;
}
};
3.844. 比较含退格的字符串
题目描述:
给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。
注意:如果对空文本输入退格字符,文本继续为空。
示例:
示例 1:
输入:s = "ab#c", t = "ad#c"
输出:true
解释:s 和 t 都会变成 "ac"。
示例 2:
输入:s = "ab##", t = "c#d#"
输出:true
解释:s 和 t 都会变成 ""。
示例 3:
输入:s = "a#c", t = "b"
输出:false
解释:s 会变成 "c",但 t 仍然是 "b"。
解答描述:
该题需要注意的是,每个#只能影响它前面的字符,退掉前面的字符,不能影响后面的字符。
所以从尾到头进行扫描,记录下当前还未使用的#个数cnt,每遇到一个#,cnt+1,每遇到一个字符cnt-1,如果cnt减为0了,而此时两个字符串对应字符不相等,说明二者不相等,返回false。或者当一个字符串遍历完了,而另一个没有时,也返回false。
代码:
class Solution {
public:
bool backspaceCompare(string s, string t) {
int n1=s.size();
int n2=t.size();
//从后往前遍历,并记录当前还剩多少个#没有应用
int i=n1-1;
int j=n2-1;
int cnt1=0;
int cnt2=0;
while(i>=0 || j>=0)
{
while(i>=0)
{
if(s[i]=='#')//当遇到#时,cnt1++
{
cnt1++;
i--;
}
else
{
if(cnt1>0)//当cnt1>0时,表明该字符需要用掉一个退格符退去
{
cnt1--;
i--;
}
else
{
break;
}
}
}
while(j>=0)
{
if(t[j]=='#')//当遇到#时,cnt1++
{
cnt2++;
j--;
}
else
{
if(cnt2>0)//当cnt1>0时,表明该字符需要用掉一个退格符退去
{
cnt2--;
j--;
}
else
{
break;
}
}
}
if(i>=0 && j>=0)//当没有遍历完且两个字符串不相等时,返回false
{
if(s[i]!=t[j])
{
return false;
}
}
else
{
if(i>=0 || j>=0)//当只有一个字符串遍历完
{
return false;
}
}
i--;
j--;
}
return true;
}
};
4.986. 区间列表的交集
题目描述:
示例:
解答描述:
代码:
5.11. 盛最多水的容器
题目描述:
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
示例:
解答描述:
这个也是第二次做了,思路就是:每次让高度较小的那边移动,才有可能找到容量更大的。
代码:
class Solution {
public:
int maxArea(vector<int>& height) {
int n=height.size();
int l=0;
int r=n-1;
int max_s=0;
while(l<r)
{
int h=min(height[l],height[r]);
int w=r-l;
max_s=max(max_s,h*w);
if(height[l]<height[r])
{
l++;
}
else
{
r--;
}
}
return max_s;
}
};