第03课丨01数组、链表、跳表的基本实现和特性

2020-06-29  本文已影响0人  阳明AI

一、数组(Array)

java,C++:    int a[100];
Python:      list = []
JavaScript:  let x = [1,2,3]

二、链表(Linked List)

image

重点!!!

链表操作复杂度:
prepend ---> O(1)
append ---> O(1)
lookup ---> O(n)
insert ---> O(1)
delete ---> O(1)

Array操作复杂度:
prepend ---> O(1)
append ---> O(1)
lookup ---> O(1)
insert ---> O(n)
delete ---> O(n)

Linked list的实现(cpp):

class LinkedList{
    Node head; //head of list

    /* Linked list Node */
    class Node {
        int data;
        Node next;

        // Constructor to create new node
        // Next is by default initialized
        // as null
        Node(int d) { data = d;}
    }
}

三、跳表(Skip List)--->以理解为主

工程中,主要在Redis中进行运用,理解其工作原理为主,对于链表的查询缺陷,访问复杂度为O(n),做了优化。

image.png

1、优化的中心思想:

2、跳表的思想:(提高链表线性查找的效率)

可以认为next的每次速度为1,一级索引的每次速度为2 在一级索引的基础上,再乘以2 对于几千个元素可以增加log(2n)个级索引

3、跳表查询的时间复杂度分析

n/2、n/4、n/8、第k级索引结点的个数就是n/(2^k)

假设索引有h级,最高级的索引有2个结点。n/(2^h)=2,从而求得h=log2(n)-1

image.png

索引的高度:logn,每层索引遍历的结点个数:3

在跳表中查询任意数据的时间复杂度就是O(logn),也就是从最朴素的原始链表的O(n)的时间复杂度降到了log2n的时间复杂度。

现实中跳表的形态:

image.png

由于增加或删除,导致索引跨度不一,而且维护成本相对较高,每增加或删除一个元素的时候,需要把它的索引都更新一遍。(时间复杂度为logn)

4、跳表的空间复杂度分析(收敛的)

image

5、工程中的应用

LRU Cache - Linked list[1][2]

Redis - Skip List[3][4]


示例1:

leetcode 283 移动零​leetcode-cn.com
快慢指针

class Solution(object):
    def moveZeroes(self, nums):
        j=0
        for i in range(len(nums)):
            if nums[i] != 0 :
                nums[j] = nums[i]
                if i != j:
                    nums[i]=0
                j+=1

示例2:

leetcode 11 盛最多水的容器​leetcode-cn.com
双指针,短的柱子移动

class Solution:
    def maxArea(self, height:[]):
        res, l, r = 0, 0, len(height) - 1
        while l < r:
            h = min(height[l], height[r])
            print('=====')
            print (h)
            print (res, l, r)
            # 先执行max(res,  h * (r - l)),在执行l + (height[l] == h),在执行r - (height[r] == h
            res, l, r = max(res,  h * (r - l)), l + (height[l] == h), r - (height[r] == h)
            print (res, l, r)
        return res

示例3:(典型的斐波垃圾数列)

leetcode 70 爬楼梯​leetcode-cn.com

class Solution:
    def climbStairs(self, n: int) -> int:
        if (n <= 2): return n
        f1, f2, f3 = 1, 2, 3
        for i in range(3, n+1):
            f3 = f1 + f2
            f1 = f2
            f2 = f3
        return f3

示例4:(练习双指针的用法)

leetcode 15 三数之和​leetcode-cn.com

class Solution(object):
    def threeSum(self, nums):
        res = []
        nums.sort()
        for i in range(len(nums)):
            if i > 0 and nums[i] == nums[i-1]:
                continue
            l , r = i + 1,len(nums)-1
            while l < r:
                s = nums[i] + nums [l] +nums[r]
                if s < 0:
                    l += 1
                elif s > 0:
                    r -= 1
                else:
                    res.append((nums[i],nums[l],nums[r]))
                    while l < r and nums[l] == nums[l+1]:
                        l += 1
                    while l < r and nums[r] == nums[r-1]:
                        r -= 1
                    l += 1
                    r -= 1
        return res

示例5:(练习怎么操作链表)

leetcode 206 反转链表​leetcode-cn.com

class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        # 申请两个节点,pre和 cur,pre指向None
        pre = None
        cur = head
        # 遍历链表,while循环里面的内容其实可以写成一行
        # 这里只做演示,就不搞那么骚气的写法了
        while cur:
            # 记录当前节点的下一个节点
            tmp = cur.next
            # 然后将当前节点指向pre
            cur.next = pre
            # pre和cur节点都前进一位
            pre = cur
            cur = tmp
        return pre

示例6:(采用快慢指针--->实用性不强,当作思维训练即可)

leetcode 141 环形链表​leetcode-cn.com

class Solution(object):
    def hasCycle(self, head):
        if(head == None or head.next == None):
            return False
        node1 = head
        node2 = head.next
        while(node1 != node2):
            if(node2 == None or node2.next == None):
                return False
            node1 = node1.next
            node2 = node2.next.next
        return True

解题思路小结:

  1. 特别懵的时候,看看是否能暴力解

  2. 想基本情况是什么,能不能化繁为简的思考?

  3. 数学归纳法的思想 ---> 递推

  4. 解决各种问题关键是找最近重复子问题:

  5. if - else

  6. for while , recursion(递归)

上一篇 下一篇

猜你喜欢

热点阅读