剑指offer 链表(上)

T6-从尾到头打印链表

用栈保存ListNode指针 CPP

或者用stack保存顺序节点的val也可以。 做此题时,第一个直观的想法是顺序读链表时每次在res列表头部插入元素,可以ac然而verctor最可怕的在头部插入,可能需要多次重新分配空间,复制很多次元素

/**
*  struct ListNode {
*        int val;
*        struct ListNode *next;
*        ListNode(int x) :
*              val(x), next(NULL) {
*        }
*  };
*/
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<int> res;
        stack<ListNode*> s;
        ListNode *p=head;
        while(p){
            s.push(p);
            p=p->next;
        }
        while(!s.empty()){
            p=s.top();
            res.push_back(p->val);
            s.pop();
        }
            
        return res;
    }
};

用栈保存val py2

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        value = []
        while listNode:
            value.append(listNode.val)
            listNode=listNode.next
        n=len(value)
        res=[]
        for i in range(n):
            res.append(value.pop()) #Python的pop()函数有返回值奥
        return res

参考

cpp中stack的函数

#include <stack>
using std::stack;
stack <类型> 变量名;
##### 接下来是一些关于栈的基本操作~
stack <int> s;(以这个为例子)
1.把元素a加入入栈:s.push(a);  
2.删除栈顶的元素:s.pop(); //返回void  
3.返回栈顶的元素:s.top();  
4.判断栈是否为空:s.empty();(为空返回TRUE)  
5.返回栈中元素个数:s.size();  
6.把一个栈清空:(很抱歉没有这个函数,你得写这些:)
while (!s.empty())
	s.pop();

cpp中vertor的函数

#include <vector>
using std::vector;
>初始化方式
vector<T> v1;     //默认构造,v1 为空
vector<T> v2(v1);      //v2 是 v1 的副本
vector<T> v3(n, i);     //v3 包含 n 个 i 的元素
vector<T> v4(n);     //v4 初始化为含有 n 个 T 类型默认值的对象
vector<int> v5 = {1,2,3,4,5,6,7};     //C++11才支持,直接值初始化,最方便
>插入元素
v5.insert(v2.begin()+4, 3);   //在指定位置,例如在第五个元素前插入一个元素
v2.insert(v2.end(), 3);   //在末尾插入一个元素
v2.push_back(9);   //在末尾插入一个元素
v2.insert(v2.begin(), 3);   //在开头插入一个元素
>删除元素
v2.erase(v2.begin()); //删除开头的元素
v2.erase(v2.begin(),v2.end); //删除[begin,end]区间的元素
v2.pop_back();   //删除最后一个元素
>其他
v.empty();    //v 为空,返回true
v.size();    //返回 v 中的个数
v.clear();     //移除容器中所有数据

py中栈是由list实现的, collections模块里有deque双向队列

list.pop()返回值是抛出的元素

py中list的函数

list.append(x)	#把一个元素添加到列表的结尾,相当于 a[len(a):] = [x]。
list.extend(L)	#通过添加指定列表的所有元素来扩充列表,相当于 a[len(a):] = L。
list.insert(i, x)	#在指定位置插入一个元素。第一个参数是准备插入到其前面的那个元素的索引,例如 a.insert(0, x) 会插入到整个列表之前,而 a.insert(len(a), x) #相当于 a.append(x) 。
list.remove(x)	#删除列表中值为 x 的第一个元素。如果没有这样的元素,就会返回一个错误。
list.pop([i])	#从列表的指定位置移除元素,并将其返回。如果没有指定索引,a.pop()返回最后一个元素。元素随即从列表中被移除。(方法中 i 两边的方括号表示这个参数是可选的,而不是要求你输入一对方括号,你会经常在 Python 库参考手册中遇到这样的标记。)
list.clear()	#移除列表中的所有项,等于del a[:]。
list.index(x)	#返回列表中第一个值为 x 的元素的索引。如果没有匹配的元素就会返回一个错误。
list.count(x)	#返回 x 在列表中出现的次数。
list.sort()	#对列表中的元素进行排序。
list.reverse()	#倒排列表中的元素。
list.copy()	#返回列表的浅复制,等于a[:]。

T25-合并两个排序的链表

我下意识的非递归版本 py2

# -*- 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 pHead1 is None and pHead2 is None:
            return pHead1
        p1 = pHead1
        p2 = pHead2
        p = ListNode(0)
        pres = p
        while p1 or p2:
            if p1 and p2:
                if p1.val<=p2.val:
                    p.next = p1
                    p1 = p1.next
                else:
                    p.next = p2
                    p2 = p2.next
            elif p1:
                p.next = p1
                break
            else:
                p.next = p2
                break
            p = p.next
        return pres.next
                    

递归版本 py2

# -*- 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 pHead1 is None:
            return pHead2
        if pHead2 is None:
            return pHead1
        pHead = ListNode(0)
        if pHead1.val<=pHead2.val:
            pHead = pHead1
            pHead.next = self.Merge(pHead1.next,pHead2)
        else:
            pHead = pHead2
            pHead.next = self.Merge(pHead1,pHead2.next)
        return pHead 

稍有不同的写法

# -*- 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 pHead1 is None:
            return pHead2
        if pHead2 is None:
            return pHead1
        if pHead1.val<=pHead2.val:
            pHead1.next = self.Merge(pHead1.next,pHead2)
            return pHead1
        else:
            pHead2.next = self.Merge(pHead1,pHead2.next)
            return pHead2

T52-两个链表的第一个公共节点

两路链表走同样的长度 py

>两个链表走到各自的尾端然后跳到另一条链表的开头,相遇时走了同样的(a+b+c)长度,同样的思路,我写的就串行用了好多个while循环,惨不忍睹,人家用了选择表达式就非常简洁 ``` # -*- coding:utf-8 -*- # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def FindFirstCommonNode(self, pHead1, pHead2): # write code here if pHead1 is None or pHead2 is None: return None p1, p2 = pHead1, pHead2 while p1!=p2: p1 = pHead2 if p1 is None else p1.next p2 = pHead1 if p2 is None else p2.next return p1 ``` ## 官方推荐 记录链表的长度 暂未实现 >分别走完两个链表,记录长度,然后长链表上一个指针从等于链表差值的位置出发,短链表从头出发,二者相遇位置为第一个共同节点

栈保存节点,然后从尾开始pop,比较 不推荐 py2

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def FindFirstCommonNode(self, pHead1, pHead2):
        # write code here
        if  not pHead1 or not pHead2:
            return None
        p1, p2 = pHead1, pHead2
        stack1,stack2 = [],[]
        while p1:
            stack1.append(p1)
            p1 = p1.next
        while p2:
            stack2.append(p2)
            p2 = p2.next
        first = None
        while stack1 and stack2:
            p1 = stack1.pop()
            p2 = stack2.pop()
            if p1==p2:
                first = p1
            else:
                break
        return first

T23-链表中环的入口节点

快慢指针 py2

设置快慢指针,都从链表头出发,快指针每次走两步,慢指针一次走一步,假如有环,一定相遇于环中某点(结论1)。接着让两个指针分别从相遇点和链表头出发,两者都改为每次走一步,最终相遇于环入口(结论2)。以下是两个结论证明:
两个结论:
1、设置快慢指针,假如有环,他们最后一定相遇。
2、两个指针分别从链表头和相遇点继续出发,每次走一步,最后一定相遇与环入口。
证明结论1:设置快慢指针fast和low,fast每次走两步,low每次走一步。假如有环,两者一定会相遇(因为low一旦进环,可看作fast在后面追赶low的过程,每次两者都接近一步,最后一定能追上)。
证明结论2:
设:
链表头到环入口长度为--a
环入口到相遇点长度为--b
相遇点到环入口长度为--c

则:相遇时
快指针路程=a+(b+c)k+b ,k>=1 其中b+c为环的长度,k为绕环的圈数(k>=1,即最少一圈,不能是0圈,不然和慢指针走的一样长,矛盾)。
慢指针路程=a+b
快指针走的路程是慢指针的两倍,所以:
(a+b)*2=a+(b+c)k+b
化简可得:
a=(k-1)(b+c)+c 这个式子的意思是: 链表头到环入口的距离=相遇点到环入口的距离+(k-1)圈环长度。其中k>=1,所以k-1>=0圈。所以两个指针分别从链表头和相遇点出发,最后一定相遇于环入口。

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def EntryNodeOfLoop(self, pHead):
        # write code here
        fast,slow = pHead,pHead
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if fast==slow:
                break
        if not fast or not fast.next:
            return None
        fast = pHead
        while fast!=slow:
            slow = slow.next
            fast = fast.next
        return fast

用set()存放节点 一般吧 py2

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def EntryNodeOfLoop(self, pHead):
        # write code here
        if not pHead:
            return None
        p1=pHead
        d = set()
        while p1:
            if p1 in d:
                return p1
            else:
                d.add(p1)
            p1 = p1.next
原文地址:https://www.cnblogs.com/yxl-2018/p/12396454.html