剑指Offer(三):从尾到头打印链表
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
输入:head = [1,3,2]
输出:[2,3,1]
1、思路
通常,这种情况下,我们不希望修改原链表的结构。返回一个反序的链表,这就是经典的“后进先出”,我们可以使用栈实现这种顺序。每经过一个结点的时候,把该结点放到一个栈中。当遍历完整个链表后,再从栈顶开始逐个输出结点的值,给一个新的链表结构,这样链表就实现了反转。
2、代码
- C++:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
vector<int> reversePrint(ListNode* head) {
stack<int> result;
vector<int> reverse;
ListNode* nodes = head;
while(nodes !=NULL){
result.push(nodes->val);
nodes = nodes->next;
}
while(!result.empty()){
reverse.push_back(result.top());
result.pop();
}
return reverse;
}
};
- Python实现:
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def printListFromTailToHead(self, listNode):
# write code here
result = []
while listNode:
result.insert(0, listNode.val)
listNode = listNode.next
return result
剑指Offer(十五):反转链表
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
1、思路
- 这个很简单,我们使用三个指针,分别指向当前遍历到的结点、它的前一个结点以及后一个结点。
- 在遍历列表时,将当前节点的 next 指针改为指向前一个元素.
2、代码
- C++:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* pReversedHead = NULL;
ListNode* pNode = head;
ListNode* pPrev = NULL;
while(pNode != NULL){
ListNode* pNext = pNode->next;
if(pNext == NULL){
pReversedHead = pNode;
}
pNode->next = pPrev;
pPrev = pNode;
pNode = pNext;
}
return pReversedHead;
}
};
- python:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
last = None
while head:
tmp = head.next
head.next = last
last = head
head = tmp
return last
LeetCode 234. 回文链表
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
1、算法思路
- 复制链表值到数组列表中。
- 使用双指针法判断是否为回文。
-
遍历链表将值复制到数组列表中。用 currentNode 指向当前节点。每次迭代向数组添加 currentNode.val,并更新 currentNode = currentNode.next,当 currentNode = null 则停止循环。
-
在 Python 中,很容易构造一个列表的反向副本,也很容易比较两个列表。因此最好使用双指针法来检查是否为回文。我们在起点放置一个指针,在结尾放置一个指针,每一次迭代判断两个指针指向的元素是否相同,若不同,返回 false;相同则将两个指针向内移动,并继续判断,直到相遇。
在编码的过程中,注意我们比较的是节点值的大小,而不是节点本身。正确的比较方式是:node_1.val == node_2.val。而 node_1 == node_2 是错误的。
2、复杂度分析
- 时间复杂度:O(n),其中 n 指的是链表的元素个数。
- 第一步: 遍历链表并将值复制到数组中,O(n)。
- 第二步:双指针判断是否为回文,执行了 O(n/2)次的判断,即 O(n)。
- 总的时间复杂度:O(2n) = O(n)。
- 空间复杂度:O(n),其中 n 指的是链表的元素个数,我们使用了一个数组列表存放链表的元素值。
3、代码实现:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
vals = []
current_node = head
while current_node is not None:
vals.append(current_node.val)
current_node = current_node.next
return vals == vals[::-1]
剑指Offer(十六):合并两个排序的链表
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
1、思路
-
先判断输入的链表是否为空的指针。如果第一个链表为空,则直接返回第二个链表;如果第二个链表为空,则直接返回第一个链表。如果两个链表都是空链表,合并的结果是得到一个空链表。
-
两个链表都是排序好的,我们只需要从头遍历链表,判断当前指针,哪个链表中的值小,即赋给合并链表指针即可。使用递归就可以轻松实现。
2、代码实现
- C++:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
//判断指针是否为空
if(pHead1 == NULL){
return pHead2;
}
else if(pHead2 == NULL){
return pHead1;
}
ListNode* pMergedHead = NULL;
if(pHead1->val < pHead2->val){
pMergedHead = pHead1;
pMergedHead->next = Merge(pHead1->next, pHead2);
}
else{
pMergedHead = pHead2;
pMergedHead->next = Merge(pHead1, pHead2->next);
}
return pMergedHead;
}
};
- Python:
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# 返回合并后列表
def Merge(self, pHead1, pHead2):
# write code here
if not pHead1:
return pHead2
if not pHead2:
return pHead1
pMergeHead = None
if pHead1.val < pHead2.val:
pMergeHead = pHead1
pMergeHead.next = self.Merge(pHead1.next, pHead2)
else:
pMergeHead = pHead2
pMergeHead.next = self.Merge(pHead1, pHead2.next)
return pMergeHead
LeetCode:移除链表
题目:删除链表中等于给定值 val 的所有节点。
示例:
输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5
解题思路:直接删除
- 首先判断head是否为空以及头结点的值是否等于给定值val
- 用pre指向下一个结点进入循环,如果pre.next.val的值与给定值val相等,那么pre指向下下个结点
- 否则,则继续指向下一个结点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeElements(self, head: ListNode, val: int) -> ListNode:
#判断头结点的值是否与删除的值相等:
while head and head.val == val:
head = head.next
if not head:
return None
pre = head
while pre.next:
if pre.next.val == val:
pre.next = pre.next.next
else:
pre = pre.next
return head