1.查找链表的等分结点(快慢指针):
1.1描述:
给定一个链表查找中间结点、第一个三等分点。。。。
1.2方法:
法一:先遍历一遍链表,使用变量i记录结点个数m,再遍历链表,每遍历一个结点,则i++,直到i==m/n;
法二:使用快慢指针,慢指针走一步,则快指针走2步或3步。。。,直到快指针不满足循环体的循环条件(循环条件很重要,并且还要分偶数链表还是奇数链表)
1.3代码实现:
仅针对法二,查找中间结点
ListNode* first_half_end(ListNode* head){
ListNode *slow,*fast;
slow=head;
fast=head;
while(fast->next!=NULL && fast->next->next!=NULL ){//前一个是偶数链表情况 后一个是奇数链表情况
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
1.4应用:
leetcode 234.回文链表 法三
2.将链表转化为数组:
2.1描述:
链表是顺序访问,无法使用两个指针实现相向访问,但是数据可以随机访问,因此可将链表转化为数组来处理。
2.2方法:
再C++中,使用vector容器来作为数组,每访问一个链表中的结点,就用emplace_back()方法,将结点放入vector容器中。
2.3代码实现:
vector<int> vals;
while(head!=nullptr){
vals.emplace_back(head->val);
head=head->next;
}
2.3应用:
leetcode 234.回文链表 法一
3.加法运算中的进制:
3.1描述:
通过计算机实现加法运算,需要注意进制。
3.2方法:
1.使用变量carry记录每位相加时产生的进位。进位的计算:carry = sum/10;
2. 每位相加后的数的计算:value=sum%10;
3. 注意:最高位的进位在循环结束后处理;
3.3代码实现:
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode *l3=new ListNode;
/*小技巧:对于链表问题,返回结果为首元结点时,通常需要先初始化头结点head;,
该指针的下一个节点指向真正的首元结点。
使用头结点的目的在于链表初始化时无可用节点值,而且链表构造过程需要指针移动,
进而会导致头指针丢失,无法返回结果。并且使用头结点能够使得循环中的代码保持一致。
*/
ListNode *p;
p=l3;
int x,y,sum=0;
int carry=0;
int val3; //记录每一位相加后的值
while(l1!=nullptr || l2!=nullptr ){
x=(l1==nullptr ? 0:l1->val);
y=(l2==nullptr ? 0:l2->val);
sum=x+y+carry;
val3=sum%10;
carry=sum/10;
p->next=new ListNode(val3);
p=p->next;
if(l1!=nullptr)
l1=l1->next;
if(l2!=nullptr)
l2=l2->next;
}
//99999+999;最高位还要进一位
if(carry==1){
p->next=new ListNode(1);;
}
return l3->next;
}
};
3.4应用:
leetcode 2.两数相加。
4.哨兵结点(dummy node):
4.1使用情况:
在很多时候,我们处理某个节点需要用到它的前驱节点,比如删除链表的某个节点 ,对于没有哨兵的单链表,当待删除的节点为链表的第一个节点, 由于没有前驱,需要进行特殊处理,从而代码的复杂性增加.而如有哨兵节点,则第一个节点的处理方式与其他节点相同,可以统一进行处理.
对于链表的处理,我们经常在头结点之前设置一个哑结点dummyHead 。我们将这个结点指向头结点。
为什么这么做?
因为在删除链表元素的时候,说不定要删除的元素中包含头结点。如果我们从头结点开始,就要把自己所站的位置删除。这就挺尴尬的了…(内心独白:让我来删除结点,结果删除的却是我自己o(╥﹏╥)o…)
为了避免这样的情况,我们设置一个哑结点,指向头结点。这样虽然浪费一点空间,但换来了大大的好处,至少不用分类讨论头结点的问题
5. 链表中的栈:
5.1 使用情况:
链表只能从头结点开始往后遍历查找结点,若是能够像数组那样从后往前查找结点,则会方便很多。通过栈能够实现这种想法。
5.2 方法:
使用STL中的stack容器作为栈。遍历链表,将结点的地址(而不是结点的值)放入stack中。
5.3 应用与代码实现:
leetcode 19.删除链表中倒数第N个结点
/**
* 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* removeNthFromEnd(ListNode* head, int n) {
//用到前一个指针pre ,创建哨兵结点
ListNode* dummy=new ListNode(0,head);
ListNode* curr=dummy;
ListNode* pre;
stack<ListNode*> stack1;
//将结点的地址放入stack容器中
while(curr!=nullptr){
stack1.push(curr);
curr=curr->next;
}
//弹出后n个结点
for(int i=0;i<n;i++){
stack1.pop();
}
//倒数第n个结点的前一个结点地址
pre=stack1.top();
pre->next=pre->next->next;
//返回哨兵结点的后一个结点
return dummy->next;
}
};