USYD COMP2123 Linked List tutorial

这周的知识点

了解以下数据结构的实现, time and space constraint

  • array implementation of a list

  • singly and doubly linked list

  • doubly linked list Stack and Queue

  • adv singly linked list stack and queue

python里的run time和function call测试方法

Tutorial

Q3 : Given a singly linked list, traverse the elements of the list in reverse order.

  • Design an algorithm that uses O(1) extra space.

首先我们需要了解题意, 是否真的要把linked list反过来.

比如 1->2->3 经过处理后变成 3->2->1.

如果只能使用O(1)的空间, 那么我们除了已经给的list的空间没有更多的地方来存储信息, 那么免不了对原本linkedlist的改动, 也就是

改变node之间next的指向.

O(1)的方法 有iterative和recursive两种解法, 推荐了解iterasive的写法.

在这之前, 先写一个helper function print_linkedlist(head)来帮忙检验. 我们默认print_linkedlist是时间O(n)空间O(1)的.


def print_linkedlist(head):

    node = head

    while(node):

        print(node.value) #traversed

        node = node.next

Iterasive method


def reverseList(head):

    current = head

    prev = None

    while(current):



        curr_next = current.next #先存next, 下一步要走的点

        current.next = prev # **改变当前点的next位置. 反转的一步!**

        prev = current #更新prev称为当前点.

        current = curr_next #更新当前点为next, 下一步要走的点.

    #理解视频: https://www.youtube.com/watch?v=sYcOK51hl-A

    old_last_node = prev

    return old_last_node

print_linkedlist(reverseList(head))

Recursive method


def reverseList(head):

    """

    return the new head with the reversed linkedlist

    """

    if head==None or head.next==None:



        return head

    old_second = self.reverseList(head.next)

    head.next.next = head

    head.next=None



    return old_second

print_linkedlist(reverseList(head))

  • Design an algorithm that uses O(sqrt(n)) extra space.

因为题目要求仅仅是reversely traverse, 有多余位置存储信息的话, 我们就可以事实上不改变node之间的联系了.


def reverse_sqrt_n(head):

    # 为了方便描述 记 K = sqrt(n)

    # # -------第一步: 找到list的长度------

    # 假设我们不知道这个list有多长, 我们首先需要获取长度信息.

    n=0

    node=head

    while node:

        n+=1

        node=node.next

    #to know how long is our linked list, time O(n), space O(1)

    k=int(n**.5)+1  #确定sqrt(n)的大小

    # 到这一步为止 time用了n, space用了1

    # ---------第二步: 存储每第K个node位置-------

    # 存储每第sqrt(k)个node

    # 一共有 k/sqrt(k)=sqrt(k)次操作, 存好了以后会使用sqrt(k)space.

    i=0

    node=self

    lsa=[node]

    node_stored_position_sequence=[] #只是为了分析而用

    count = 0

    while node:

        i+=1

        count+=1

        if i==k:

            lsa.append(node)

            node_stored_position_sequence.append(count) #只是为了分析而用

            i=0

        last_node=node

        node=node.next

    if i>0:

        lsa.append(last_node)

    # print(node_stored_position_sequence)

    # 如果n=100的话,这里node_stored_position_sequence应该存了 [11, 22, 33, 44, 55, 66, 77, 88, 99]个node.

    # 到这一步为止 time用了2n, space用了K

    # -------第三步: 反向打印------

    # 我们已经存了每第sqrt(n)个node的位置, 那么要如何反过来呢?

    # 每一次我们pop一个node, 并且记录上一次被pop的那个.

    # 处理最后一个node就是:顺序 node = node.next地把结果存起来,存到之前存的那个为止

    # 比如我们存22号node, 就一路 node = node.next 的把结果保存到一个list里, 直到遇到33号为止

    # 存完[22, 23, 24... 32]之后, 我们反着打印. 反着打印花的时间是K.

    # 这样我们操作K次, 每次使用K的空间.

    # 一共space cost是K, time cost则是n+n + K*K = 3n =  O(n).

    start_node=lsa.pop()

    print(start_node.value)

    while lsa: # this happens K times. K = sqrt(K)

        last_printed_node=start_node

        start_node=lsa.pop()

        node=start_node

        ssa=[]

        while node!=last_printed_node:

            ssa.append(node)

            node=node.next

        # [print(v.value, end=" ") for v in ssa]

        # 如果打印的话, 这一步应该打印 sqrt(n) 次, 每一次打印一个 sqrt(n)长度的数组

        ssa.reverse()

        for node in ssa:

            print(node.value)

Q5 : Consider the problem of given an integer n, generating all possible permutations of {1,2,3...n}

  • 了解这道题里的复杂度分析是最重要的一点.

举个例子

permute(3) = [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]

显然 如果已经知道了permute(2), 那permute(3)则只需要在每一个permute(2)的任意一位置加入3这个数字 ,

[[1, 2], [2, 1]]

[[1,2,3], [1,3,2], [3,1,2]

[[2,1,3], [2,3,1], [3,2,1]].

所以, 时间复杂度由T(n) = n * T(n-1) + O(1) , 可以推出时间复杂度是 O(N!)

空间: O(N!) 因为要记录排列组合本身就需要O(N!)这么大的空间

  • recursive method(推荐)

def permute(n):

    '''

    :type n: int

    :rtype: List[List[int]]

    return the list contains each lists of permutation

    from {1,2,..n}

    '''

    l = []

    s = []

    v = [0 for i in range(n+1)]

    # 我们不用index 0的位置, 因为题目要求permute从1到n

    # 1 based index

    def dfs(l,s,v,index):

        #start is for the beginning position

        if index==n+1:

            l.append(s[:]) #记录当前组合

            return

        else:

            for i in range(1,n+1):

                if v[i]==0:

                    s.append(i)

                    v[i]=1

                    dfs(l,s,v,index+1)

                    v[i]=0

                    s.pop() #回溯操作

    dfs(l,s,v,1)

    return l

print(permute(3))

  • iterative method(Heap's algorithm)

def permute_iterative_heap_s_algorithm(n):

    """

    :type n: int

    :rtype: List[List[int]]

    """

    c = [0 for i in range(n)]

    A = [i+1 for i in range(n)]

    i = 0

    res= [A[:]]

    while i < n:

        if  c[i] < i:

            if i%2==0:

                A[0],A[i] = A[i], A[0]

            else:

                A[c[i]], A[i] = A[i],A[c[i]]

            res.append(A[:])

            c[i] += 1

            i = 0

        else:

            c[i] = 0

            i += 1



    return res

你可能感兴趣的:(USYD COMP2123 Linked List tutorial)