zoukankan      html  css  js  c++  java
  • 剑指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
    
  • 相关阅读:
    当函数中传递的参数数量不定时,获取传递给函数的参数信息
    redis分页摘抄
    redis分页
    返回数组中指定的一列,将键值作为元素键名array_column
    PHP操作Redis常用技巧总结
    php面试中的经典问题
    php 依赖注入的实现
    10分钟快速理解依赖注入
    PHP 依赖注入,依赖反转 (IOC-DI)
    PHP控制反转(IOC)和依赖注入(DI)
  • 原文地址:https://www.cnblogs.com/yxl-2018/p/12396454.html
Copyright © 2011-2022 走看看