描述
输入一个链表,反转链表后,输出新链表的表头。
输入: {4,1,2,3}
返回值: {3,2,1,4}
本题看似是一道很简单的题,很多人刷题之路可能是从这道题开始,但如果不看题解,能独立想清楚却并不是那么容易,此题考查的是通过对链表指针的操作,实现链表反转。建议看完实现思路后,自己画一遍过程。
实现思路
使用三个指针,来实现
1、cur指针指向待反转链表的第一个节点
2、pre指针指向已反转链表的最后一个节点
3、nex指针用以保存待反转链表的下一个节点
实现过程:
1、记录下一个节点的位置 nex=cur-> next
2、当前带反转链表的第一个节点的next指向已反转链表的最后一个节点 cur->next=pre
3、更新指针位置 pre=cur cur=nex
循环终止条件:cur=nullptr
示例代码
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
ListNode* cur=pHead;
ListNode* pre=nullptr;
ListNode* nex=nullptr;
while(cur){
nex=cur->next;//保存位置
cur->next=pre;
pre=cur;
cur=nex;
}
return pre;
}
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
//判断链表是否有环,使用快慢指针法
ListNode* fast=head;
ListNode* slow=head;
while(fast&&fast->next){
fast=fast->next->next;
slow=slow->next;
if(fast==slow){
return true;
}
}
return false;
}
};
方法一:头插法(不使用新的栈保存临时的值)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
/**
*
* @param head1 ListNode类
* @param head2 ListNode类
* @return ListNode类
*/
ListNode* addInList(ListNode* head1, ListNode* head2) {
// write code here
// 为了对齐位置,我们先使用栈分别保存两个链表中节点的值
stack<int> stk1;
stack<int> stk2;
ListNode* head=new ListNode(-1);
ListNode* tail=head;
while(head1){
stk1.push(head1->val);
head1=head1->next;
}
while(head2){
stk2.push(head2->val);
head2=head2->next;
}
int carry=0; //考虑进位
while(!stk1.empty()||!stk2.empty()||carry!=0){
int a=0,b=0;
if(!stk1.empty()){
a=stk1.top();
stk1.pop();
}
if(!stk2.empty()){
b=stk2.top();
stk2.pop();
}
int sum=a+b+carry;
int num=sum%10;
carry=sum/10;
ListNode* tmp=new ListNode(num);
tmp->next=head->next;
head->next=tmp;
}
return head->next;
}
};
方法二:尾插法 注意头插和尾插的区别,头插逆序,尾插顺序
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
/**
*
* @param head1 ListNode类
* @param head2 ListNode类
* @return ListNode类
*/
ListNode* addInList(ListNode* head1, ListNode* head2) {
// write code here
// 为了对齐位置,我们先使用栈分别保存两个链表中节点的值
stack<int> stk1;
stack<int> stk2;
stack<int> stk3;
ListNode* head=new ListNode(-1);
ListNode* tail=head;
while(head1){
stk1.push(head1->val);
head1=head1->next;
}
while(head2){
stk2.push(head2->val);
head2=head2->next;
}
int carry=0; //考虑进位
while(!stk1.empty()||!stk2.empty()||carry!=0){
int a=0,b=0;
if(!stk1.empty()){
a=stk1.top();
stk1.pop();
}
if(!stk2.empty()){
b=stk2.top();
stk2.pop();
}
int sum=a+b+carry;
int num=sum%10;
carry=sum/10;
stk3.push(num);
}
while(!stk3.empty()){
ListNode* tmp=new ListNode(stk3.top());
tail->next=tmp;
tail=tmp;
stk3.pop();
}
return head->next;
}
};
大致过程可以分解为
1、找到待翻转的k个节点(注意:若剩余数量小于 k 的话,则不需要反转,因此直接返回待翻转部分的头结点即可)。
2、对其进行翻转。并返回翻转后的头结点(注意:翻转为左闭又开区间,所以本次反转的尾结点其实就是下一反转的头结点)。
3、对下一轮 k 个节点也进行翻转操作。
4、将上一轮翻转后的尾结点指向下一轮翻转后的头节点,即将每一轮翻转的k的节点连接起来。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类
* @param k int整型
* @return ListNode类
*/
ListNode* reverseKGroup(ListNode* head, int k) {
// write code here
// 参考链表反转的思路
if(!head||!head->next)
return head;
ListNode* tail=head;
for(int i=0;i<k;i++){
if(tail==nullptr){
return head;
}
tail=tail->next;
}
//关键代码是接下来三行,注意理解
ListNode* newHead=reverse(head,tail);
head->next=reverseKGroup(tail, k);
return newHead;
}
ListNode* reverse(ListNode* head,ListNode* tail){
ListNode* pre=nullptr;
ListNode* cur=head;
ListNode* nex=nullptr;
while(head!=tail){
nex=cur->next;
cur->next=pre;
pre=cur;
cur=nex;
}
return pre;
}
};
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类
* @return ListNode类
*/
ListNode* deleteDuplicates(ListNode* head) {
// write code here
if(head==nullptr){
return nullptr;
}
if(head->next&&head->val==head->next->val){
while(head->next&&head->val==head->next->val)
{
head=head->next;
}
return deleteDuplicates(head->next);
}
head->next=deleteDuplicates(head->next);
return head;
}
};
使用快慢指针找出中点,reverse后半部分,然后逐个比较
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类 the head
* @return bool布尔型
*/
bool isPail(ListNode* head) {
// write code here
ListNode * fast=head;
ListNode* slow=head;
while(fast&&fast->next){
fast=fast->next->next;
slow=slow->next;
}
if(fast!=nullptr){//如果不为空,说明链表长度为奇数,slow向后走一个
slow=slow->next;
}
slow=reverse(slow);
fast=head;
while (slow != nullptr) {
//然后比较,判断节点值是否相等
if (fast->val != slow->val)
return false;
fast = fast->next;
slow = slow->next;
}
return true;
}
ListNode* reverse(ListNode* head){
ListNode* prev = nullptr;
while (head != nullptr) {
ListNode* next = head->next;
head->next = prev;
prev = head;
head = next;
}
return prev;
}
};
class Solution {
public:
/**
*
* @param n int整型
* @param m int整型
* @return int整型
*/
int ysf(int n, int m) {
// write code here
ListNode* head=new ListNode(1);
ListNode* tail=head;
for(int i=2;i<=n;i++){
ListNode* node=new ListNode(i);
tail->next=node;
tail=node;
}
tail->next=head;
ListNode* index=head;
ListNode* pre=tail;
int count=0;
while(index->next&&index->next!=index){
count++;
ListNode* next=index->next;
if(count==m){
pre->next=pre->next->next;
count=0;
}
pre=index;
index=next;
}
return index->val;
}
};