【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)
206. Reverse Linked List
Reverse a singly linked list.
Example:
Input:
1->2->3->4->5->NULL
Output:
5->4->3->2->1->NULL
Follow up:
A linked list can be reversed either iteratively or recursively. Could you implement both?
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
//迭代法
//O(n),O(1)
class
Solution
{
public
:
ListNode
*
reverseList
(
ListNode
*
head
)
{
if
(
head
==
nullptr
)
return
nullptr
;
ListNode
*
pre
=
nullptr
,
*
cur
=
head
,*
next
;
//三个指针分别保存之前,当前,下一个结点
while
(
cur
)
{
next
=
cur
->
next
;
//保存原链表该结点的下一个结点,以免变换指向之后无法遍历到下一个结点
cur
->
next
=
pre
;
//变换指向
pre
=
cur
;
//更新指针
cur
=
next
;
//更新指针
}
return
pre
;
//最后pre指向最后一个结点,cur指向null
}
};
//递归法(不太好理解)
/*
O(n) O(n)(来自递归栈)
Assume from node nk+1 to nm had been reversed and you are at node nk.
n1 → … → nk-1 → nk → nk+1 ← … ← nm
We want nk+1’s next node to point to nk.
So,
nk.next.next = nk;
*/
class
Solution
{
public
:
ListNode
*
reverseList
(
ListNode
*
head
)
{
if
(
head
==
nullptr
||
head
->
next
==
nullptr
)
return
head
;
ListNode
*
p
=
reverseList
(
head
->
next
);
//递归之后为从后往前开始转向
head
->
next
->
next
=
head
;
head
->
next
=
nullptr
;
return
p
;
}
};
92
.
Reverse Linked List II
Reverse a linked list from position
m
to
n
. Do it in one-pass.
Note:
1 ≤
m
≤
n
≤ length of list.
Example:
Input:
1->2->3->4->5->NULL,
m
= 2,
n
= 4
Output:
1->4->3->2->5->NULL
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
/*
问题:翻转链表
2
(位置
m~n
翻转)
方法:对
m~n位置处的链表进行翻转,然后连接m-1位置与n位置,m位置与n+1位置
例:
Input: 1 ->
2
-> 3 ->
4
-> 5 -> NULL, m = 2, n = 4
翻转得,
1 <->
2(m)
<- 3 <-
4(n)
5 -> NULL
连接得,
1 ->
4
-> 3 ->
2
-> 5 -> NULL
*/
class
Solution
{
public
:
ListNode
*
reverseBetween
(
ListNode
*
head
,
int
m
,
int
n
)
{
//
异常情况处理(严格来说,还需判断
m,n
值是否超出链表长度
,
题目已经有此条件)
if
(!
head
||
!
head
->
next
||
m
<
0
||
n
<
0
||
m
>=
n
)
return
head
;
//
prehead的应用:
头结点前的结点,方便索引,方便分析(链表用1开头+prehead分析较好,序号可以与步数对应起来)
//
且指向了链表的头结点,当
m=1
时,原头结点被换到后面,若返回
head
会出错,
//
而用
prehead
会指向新头结点,故返回
prehead.next
不会出错
ListNode prehead
(
0
);
prehead
.
next
=
head
;
ListNode
*
cur
=
&
prehead
;
for
(
int
i
=
1
;
i
<=
m
-
1
;
i
++)
cur
=
cur
->
next
;
//
最后
cur
处在
m-1
位置
ListNode
*
pre
=
cur
;
ListNode
*
next
;
cur
=
cur
->
next
;
//
让
cur
处在
m
位置
ListNode
*
prefirst
=
pre
,
*
first
=
cur
;
//
保存
m-1
位置和
m
位置处的结点
for
(
int
i
=
m
;
i
<=
n
;
i
++)
//
翻转位置
m~n
处的链表
{
next
=
cur
->
next
;
cur
->
next
=
pre
;
pre
=
cur
;
//
更新指针
cur
=
next
;
//
更新指针
}
//
退出时,
pre
在
n
处,
cur
在
n+1
处
prefirst
->
next
=
pre
;
//
连接
m-1
与
n
位置
first
->
next
=
cur
;
//
连接
m
与
n+1
位置
return
prehead
.
next
;
}
};