大家好哇!我是湫湫。
进入正题,最近刷了一些基础题,想通过文章记录自己的学习过程。
本专栏主要加载了一些不同类型的C++题。
非常感谢大家的阅读,如果有不对的地方欢迎指正。
目录
一、快慢指针
1、两个指针同向而行,按不同的速度或策略移动。
2、常用于检测是否成环,查找链表某些特定节点等。
3、明确指针的初始位置,移动速度/策略,停止条件,仔细处理边界情况。
题目1(141.环形链表):
给你一个链表的头节点 head
,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos
不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回true。否则,返回false。
题解:
如下图所示,每次fast走两步,slow走一步
如若链表有环,它们就会在链表上某一个节点处相遇----判断链表有环的条件
如若没有环,最后呢fast会指向NULL。
解题:
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *slow = head, *fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (fast == slow)
return true;
}
return false;
}
};
注:如若存在环,得满足fast和fast->next需要不为空。
题目2(876.链表的中间结点):
给你单链表的头结点 head
,请你找出并返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
题解:
如下图所示,此题与上面描述的题类似,主要不同在
当快指针指针走完所有结点,此时慢指针正好位于中间结点。
解题:
class Solution {
public:
ListNode* middleNode(ListNode* head) {
if (!head || !head->next) {
return head;
}
auto fast = head;
auto slow = head;
while (fast && fast->next) {
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
};
二、左右指针
1、两个指针从两端想向而行,相遇时结束
2、相遇时,可能已经遍历了某个特定部分或者满足了某个条件
3、根据题目条件确定哪个指针走
题目1(11.盛最多水的容器)
给定一个长度为 n
的整数数组 height
。有 n
条垂线,第 i
条线的两个端点是 (i, 0)
和 (i, height[i])
。
找出其中的两条线,使得它们与 x
轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:不能倾斜容器。
题解:
根据题意画出以下图形示例
一般的方法是求解第一个柱子和后面柱子依次构成的面积,直到第一个柱子和后面的柱子都组合完成。然后再用第二个柱子和它后面的柱子组合求解一下面积,以此类推,找到求解中面积最大的,显然此方法可行,但费时费力。
就很有必要用左右指针的思想
water=min(height[1],height[8])*(8-1)
->w(i,j)=min(height[i],heigth[j])*(j-i);i<j
->max(w(i,j))
在w(i,j)=min(height[i],heigth[j])*(j-i);i<j中,(j-i)在不断减小,min(height[i],heigth[j])不变或者变小,对应的w(i,j)的值也会减小,因此,只有min(height[i],heigth[j])变大,就如下图所示时w(i,j)的值最大,移动的结束条件是当i,j相遇时,就可不用移动。
结论:移动对应柱子比较矮的指针。
解题:
class Solution {
public:
int maxArea(vector<int>& height) {
int l = 0, r = height.size() - 1;
int ans = 0;
while (l < r) {
int area = min(height[l], height[r]) * (r - l);
ans = max(ans, area);
if (height[l] <= height[r]) {
++l;
}
else {
--r;
}
}
return ans;
}
};