1.双指针
1.1快慢双指针
快慢双指针常用来解决循环问题,或是查找中间节点
1.1.1循环链表(141. 环形链表 - 力扣(LeetCode))
解题思路:
1.定义快慢指针fast和slow,让fast每次走两步,slow每次走一步
2.如果(slow==fast)相遇则证明有环,如果fast为空,则证明无环
为什么有环一定相遇?
因为我们假设两人赛跑,慢的人相对快的人就是静止的,如果有环,快慢人之间的距离就会不断减小,所以有环一定相遇
//C++版
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; // 访问到了链表末尾,无环
}
};
//C语言
typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head) {
ListNode*fast,*slow;
fast=slow=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
return true;
}
return false;
}
1.1.2中间节点(876. 链表的中间结点 - 力扣(LeetCode))
解题思路:
1.定义快慢指针fast和slow,让fast每次走两步,slow每次走一步
2.如果fast为空,则证明有此时的slow即为所求位置
//C++版
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode* slow = head;
ListNode* fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
};
//C语言版
typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
ListNode*fast,*slow;
fast=slow=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
1.2对撞指针
1.2.1双变化趋势对撞指针(11. 盛最多水的容器 - 力扣(LeetCode))
解题思路:
设两指针 right , left ,分别指向⽔槽板的最左端以及最右端,此时容器的宽度为 right - left 。由于 容器的⾼度由两板中的短板决定,因此可得容积公式 : v = (right - left) * min( height[i], height[j])
注意点:
1.此时的容器宽度只会变小
2.当容器高度发生变化时,容积才会变化
3.不能改变数组的顺序
//C++版本
class Solution {
public:
int maxArea(vector<int>& height) {
int right = height.size() - 1, left = 0, ret = 0;
while (right > left)
{
int v1 = min(height[right], height[left]) * (right - left);
ret = max(v1, ret);
if (height[right] < height[left])
right--;
else
left++;
}
return ret;
}
};
//C语言版本
#define MIN(a, b) ((b) < (a) ? (b) : (a))
#define MAX(a, b) ((b) > (a) ? (b) : (a))
int maxArea(int* height, int heightSize) {
int ans = 0, left = 0, right = heightSize - 1;
while (left < right) {
int area = (right - left) * MIN(height[left], height[right]);
ans = MAX(ans, area);
height[left] < height[right] ? left++ : right--;
}
return ans;
}
1.2.2单变化趋势对撞指针(611. 有效三角形的个数 - 力扣(LeetCode))
如果能构成三⻆形,需要满⾜任意两边之和要⼤于第三边。但是实际上只需让较⼩的两条边 之和⼤于第三边即可。
解题步骤:
1.定义左右指针,即数组下标(lef=0,right=nums.size()-1),来固定三角形种
2.定义变量i来表示中间的边如果nums[i]+nums[left]>nums[right]则可以组成三角形
3.让left不断接近i
class Solution {
public:
int triangleNumber(vector<int>& nums) {
sort(nums.begin(),nums.end());//让数组从小到大排列
int n=nums.size()-1,ret=0;
for(int right=n;right>=2;right--)//固定right最长边
{
int left=0,i=right-1;//固定第二长边i
while(left<i)//让left不断变化
{
if(nums[i]+nums[left]>nums[right])//成立则说明可以组成三角形
{
ret+=i-left;//即[left,i)都可以组成三角形
i--;
}
else//不成立让最短边边长
{
left++;
}
}
}
return ret;
}
};