下面是我做的一些题,用到了不同的方法和知识点
方法:快慢指针、双指针、栈、枚举等等
知识点:
stack()的常用方法:
头文件#include <stack>
定义:stack<typename> name
栈是一种后进先出的数据结构、在STL中可以通过top()来方位栈顶元素:
例如:
#include <bits/stdc++.h>
#include <stack>
using namespace std;
int main(){
stack<int> st;//定义一个int型的stack,名字为st;
for(int i = 0; i < 5; i++){
st.push(i);
}//给栈依次赋值为01234;
cout<<st.top()<<endl;//输出top元素:4
return 0;
}
stack常用函数:
stack.push(x);//放入元素x
stack.top();//返回栈顶元素
stack.pop();//弹出栈顶元素
stack.empty();//检查stack是否为空,是则返回true,反之,则False
stack.size();//返回大小
stack 用来模拟实现一些递归,防止程序对栈内存的限制而导致程序运行出错。
第一题:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
1.枚举
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(!head){
return head;
}
ListNode* end = head;//定义一个end指向head在的位置
while(end->next)//保证end有下一位,直到删除所用重复元素,
{
//判断当前end的值和end下一个节点的值,是否相同,如果相同就删除当前的节点
if(end->val==end->next->val){
end->next = end->next->next;
}
else end = end->next;
}
return head;
}
};
//思路:定义一个指针,它不断前进,如果它在前进的情况下,当前值等于下一位的值,那么就把当前的下一位指向下一位的后一位,这样就删除了相同的元素,但是这样只能一次性删除一个。最后在指针的不断前进下,最后删除了所用相同元素。
2.双指针:
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(!head){
return head;
}
ListNode* end = head,*end1 = head->next;;//定义一个end指向head在的位置
while(end1)
{
if(end->val != end1->val){
end->next = end1;
end = end->next;
}
end1 = end1->next;
}
end->next = end1;
return head;
}
};
//思路:定义两个指针,一个在前,一个在后,它们不断以相同的速度前进。我们的解题思路就是把一片一样的元素弄成一个,保证前一个和后一个的值一直是不同的,就解决了重复的问题。那么我们怎么保证一片重复元素是一个呢?(滑动窗口)假设后一个已经移动到了一片重复元素,前一个在元素相同的情况下,不移动后一个元素,只移动前一个,直到前一个指向不同元素,那么就把后一个的下一位指向前一个就可以了。,这样我们就在前指针和后指针不断前进的条件下,删除相同元素了。最后前指针一定会变成空指针,因此我们要把后指针的下一位指向前指针(null)。
第二题: 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* end = nullptr;//定义一个末尾节点end
ListNode* l= head;//定义一个l,用于边遍历数组
while(l){//保证star存在的前提下,向前移动一位
//把star指向的下一位和值赋值到我们新建的链表上:
ListNode* r = l->next;//r指向l的下一位
l->next = end;//把l的下一位指向后面新建的end
//移动end和l,使得循环不断前进,形成反转链表;
end = l;
l = r;
}
return end;
//思路:在原来的链表的第一位的左边建立一个链表节点end(值为null),在定义一个指针为l指向头结点,在循环中保证l存在的前提下,然后定义一个r指针为l的下一位,使得l的下一位指向我们建立的end指针,用于反转指针,最后根据循环移动end、l、r(r只有满足循环才会继续移动),这样我们就得到了一个反转链表;最后end指向原来链表的最后一个,r和l为空指针。因此返回end就是反转链表的头结点了;
}
};
//形象表达:原链表:12345(1-》2-》3-》4-》5-》null); 改变它们的指向方式,在最左边建立一个null: null,12345null; null1,2345null; null12,345null; null123,45null; null1234,5null; null12345,null;现在是5-》4-》3-》2-》1-》null
第三题:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
1.常规方法:
class Solution {
public:
int getLength(ListNode* head) {//得到链表的长度
int length = 0;
while (head) {
++length;
head = head->next;
}
return length;
}ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode(0, head);//在head指针前面定义一个指针,防止在删除第一个链表时的特殊情况
int length = getLength(head);
ListNode* cur = dummy;//定义一个指针cur遍历要删除的链表的前一个
for (int i = 1; i < length - n + 1; ++i) {
cur = cur->next;
}//从cur开始、遍历到要删除的链表的前一个
cur->next = cur->next->next;//删除链表
ListNode* ans = dummy->next;//定义一个ans指针指向dummy现在的下一位,如果删除的是第一位则dummy的下一位指向的是第二位,反之则是head。
delete dummy;//删除定义的dummy
return ans;
}
};//思路:遍历一遍链表,得到链表的个数length,然后遍历到要删除元素的前一位,把它的的下一位指向下一位的下一位,但是为了防止删除头结点的特殊情况,我们在头结点前面定义一个dummy,这样以dummy开始遍历,就可以把删除头结点和其他节点看成一种情况了,最后删除dummy,返回ans;
//核心片段:
for (int i = 1; i < length - n + 1; ++i) {
cur = cur->next;
}//从cur开始、遍历到要删除的链表的前一个
cur->next = cur->next->next;//删除链表2.栈
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode(0, head);//在head前定义一个节点dummy
stack<ListNode*> stk;//定义一个栈
ListNode* cur = dummy;//定义一个指针cur指向dummy,cur用于遍历
while (cur) {
stk.push(cur);
cur = cur->next;
}//把链表的指针信息放入栈中,从cur指针开始
for (int i = 0; i < n; ++i) {
stk.pop();
}//根据先进后出的原则,弹出我们要删除的元素包含它后面的元素,此时top为删除元素的前一位
ListNode* prev = stk.top();//定义一个指针prev指向现在top的指针信息
prev->next = prev->next->next;//删除我们要删除的节点
ListNode* ans = dummy->next;//定义ans指针由于返回最终结果
delete dummy;
return ans;//删除之前定义的dummy,返回结果
}
};//思路:定义一个栈由于记录链表每个节点的地址,由于我们是删除倒数第几个元素,结合栈的性质就可以很容易的得到要删除元素的前一个的地址,最后删除链表元素就可以了;
//核心片段:
for (int i = 0; i < n; ++i) {
stk.pop();
}//根据先进后出的原则,弹出我们要删除的元素包含它后面的元素,此时top为删除元素的前一位
ListNode* prev = stk.top();//定义一个指针prev指向现在top的指针信息
prev->next = prev->next->next;//删除我们要删除的节点3.快慢指针
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode(0, head);
ListNode* first = head;
ListNode* second = dummy;
for (int i = 0; i < n; ++i) {
first = first->next;
}
while (first) {
first = first->next;
second = second->next;
}
second->next = second->next->next;
ListNode* ans = dummy->next;
delete dummy;
return ans;
}
};
//利用快慢指针:删除倒数第n个元素,由于快指针比慢指针快n,因此当first与second都以一步步的速度前进时,first到达了null时,second的就会到达删除元素的前一位,然后删除元素就可以了//核心片段:
ffor (int i = 0; i < n; ++i) {
first = first->next;
}
while (first) {
first = first->next;
second = second->next;
}
second->next = second->next->next;