206 反转链表
思路:
/**
反转一个单链表。
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
*/
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* pre=NULL;//指向当前元素的前一个元素
ListNode* cur=head; //cur当前遍历元素 next当前元素的下一个元素
//处理链表为空的情况
if(cur==NULL)
return NULL;
while(cur!=NULL)
{
ListNode* next = cur->next;
cur->next = pre; //更新当前元素的next指针
pre=cur;
cur=next;
}
return pre;//当前cur为null,pre指向5 就是链表的头结点
}
};
/**
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
1 ≤ m ≤ n ≤ 链表长度。
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
*/
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n) {
ListNode* pre=NULL;//指向当前元素的前一个元素
ListNode* cur=head; //cur当前遍历元素 next当前元素的下一个元素
//处理链表为空的情况
if(cur==NULL)
return NULL;
//先找到要变换的cur
ListNode* toppre=NULL;
pre = cur;
cur = cur->next;
for(int i=1;i<m;i++)
{
if(i==m-1)
toppre=pre;//存着要变换位置的头结点的前一个节点
pre=cur;
cur=cur->next;
}
ListNode* top=pre;//存着要换位置的头节点,待会指向最后的数
for(int i=1; i<=n-m; i++)
{
//旋转链表
ListNode* next = cur->next;
cur->next=pre;
pre=cur;
cur=next;
}
top->next=cur;
if(toppre!=NULL)
{
toppre->next= pre;
return head;
}
else
return pre;
}
};
思路:
设置链表的虚拟头结点
/**
删除链表中等于给定值 val 的所有节点。
输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5
*/
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
//设置链表的虚拟头结点,避免头结点特殊处理
ListNode* dummyHead=new ListNode(0);
dummyHead->next = head;
if(head==NULL)
return NULL;
ListNode* pre=dummyHead; //处理节点的前一个节点
ListNode* cur=head; //当前处理的节点
while(cur!=NULL)
{
if(cur->val==val)
{
pre->next=cur->next;
}else
pre=cur;
cur=pre->next;
}
//释放虚拟节点内存
ListNode* ret= dummyHead->next;
delete dummyHead;
return ret;
}
};
/**
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
给定 1->2->3->4, 你应该返回 2->1->4->3
*/
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
if(head == NULL)
return NULL;
ListNode* pre= dummyHead; //交换的前一个节点
ListNode* node1= head;//交换的第一个节点
ListNode* node2= node1->next;//交换的第二个节点
while(node2!=NULL)
{
ListNode* next=node2->next;
pre->next=node2;
node2->next=node1;
node1->next=next;
pre=node1;
if(pre!=NULL&& pre->next!=NULL)
{
node1=pre->next;
node2=node1->next;
}else
break;
}
ListNode* ret=dummyHead->next;
delete dummyHead;
return ret;
}
};
/**
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
链表至少包含两个节点。
链表中所有节点的值都是唯一的。
给定的节点为非末尾节点并且一定是链表中的一个有效节点。
*/
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
void deleteNode(ListNode* node) {
//由于给定的只有一个节点node,所以我们没办法获得节点的前一个指针
//做法:将后一个节点的值赋值给这个节点,删除后一个节点即可
node->val = node->next->val;
ListNode* delNode=node->next;
node->next =delNode->next;
return;
}
};
思路:
不停的让p和q同步向前移动
直到q节点为NULL,p就是要删除节点的前一个节点
/**
给定一个链表,删除链表的倒数第n个节点,并且返回链表的头结点。
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
*/
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyNode=new ListNode(0);
dummyNode->next = head;
if(head==NULL)
return NULL;
//链表+双指针 p,q指针间隔为n 同步移动p,q 当q为NULL时,p就是要删除的元素
ListNode* pre = dummyNode;
ListNode* p= dummyNode->next;
ListNode* q= p;
for(int i=0; i<n; i++)
q=q->next;
while(q!=NULL)
{
pre=p;
p=p->next;
q=q->next;
}
pre->next = p->next; //删除节点p
delete p;
ListNode* ret = dummyNode->next;
delete dummyNode;
return ret;
}
};
2 两数相加
/*
给出两个 非空 的链表用来表示两个非负的整数。
其中,它们各自的位数是按照 逆序 的方式存储的,
并且它们的每个节点只能存储 一位 数字。
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
*/
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* head=new ListNode(0);//存储结果的头结点
ListNode* cur = head;
int addOne = 0;//是否前一位有进制
int sum;
ListNode* res;
//思路就是遍历l1和l2的每一个节点,计算结果和进制
while(l1!=NULL || l2!=NULL)
{
if(l1==NULL)
{
sum = l2->val+addOne;
res = new ListNode(sum%10);
l2=l2->next;
}else if(l2==NULL)
{
sum = l1->val+addOne;
res = new ListNode(sum%10);
l1=l1->next;
}else
{
sum = l1->val+l2->val+addOne;
res = new ListNode(sum%10);
l1=l1->next;
l2=l2->next;
}
cur->next = res;
addOne= sum/10;
cur = cur->next;
}
//看一下是否还有进制
if(addOne!=0)
{
ListNode* res = new ListNode(addOne);
cur->next = res;
}
return head->next;
}
};