算法01-数组、链表、跳表的基本实现和特性

《算法练习-文章汇总》

数组:在内存中开辟了一段连续的地址,每一个地址就直接可以通过内存管理器进行访问,访问某一个元素的时间复杂度为o(1),

Java,C++: int a[100];

Python: list=[]

JavaScript: let x = [1,2,3]

array 时间复杂度

prepend O(1)
append O(1)
lookup O(1)
insert O(n)
delete O(n)

Linked List

class LinkedList{

     Node head;
     class Node {
     int data;
     Node next;
     Node(int d){data = d;}
     }
}

linked list时间复杂度

prepend O(1)
append O(1)
lookup O(n)
insert O(1)
delete O(1)

skip list跳表:只能用于元素有序的情况。跳表对标的是平衡树(AVL Tree)和二分查找,是一种插入/删除/搜索都是Olog(n)的数据结构。1989年出现。它最大的优势是原理简单,容易实现,方便扩展,效率更高。因此在一些热门的项目里用来替代平衡树,如Redis、LevelDB等。

一般加速方式是升维,一维变二维,升维思想+空间换时间。

跳表查询的时间复杂度分析:n/2、n/4、n/8、第k级索引结点的个数就是n/(2…k),假设索引有h级,最高级的索引有2个结点。n/(2h)=2,从而求得h=log2(n)-1;

在跳表中查询任意数据的时间复杂度就是O(logn),空间复杂度为O(n)
跳表时间复杂度

prepend O(log2(n))
append O(log2(n)
lookup O(log2(n)
insert O(log2(n)
delete O(log2(n)

LRU缓存机制

为什么redis中使用跳表(skiplist)

练习步骤

题目移动零:https://leetcode-cn.com/problems/move-zeroes/

1.5-10分钟:读题和思考

2.有思路:自己开始做和写代码;不然马上看题解!

3.默写背诵、熟练

4.然后开始自己写(闭卷)

5.五遍,五毒神掌

6.去掉cn来到国际站https://leetcode.com/problems/move-zeroes/

移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:

输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:

必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/move-zeroes

思路:
1.loop count zeros
2.开心数组 loop
3.index

单次循环

void moveZeroes(int* nums, int numsSize){
    int i, k;
    int j = 0;
    for(i = 0;i< numsSize;i++){
          if(nums[i] != 0){
             nums[i] = k;
             nums[j] = nums[i];
             k = nums[j];
             j++;
          }
    }
}

两次循环

public void moveZeroes(int[] nums) {
    if (nums == null || nums.length == 0) return;        

    int insertPos = 0;
    for (int num: nums) {
        if (num != 0) nums[insertPos++] = num;
    }        

    while (insertPos < nums.length) {
        nums[insertPos++] = 0;
    }
}

滚雪球

class Solution {
     public void moveZeroes(int[] nums) {
        int snowBallSize = 0; 
        for (int i=0;i 0) {
                int t = nums[i];
                nums[i]=0;
                nums[i-snowBallSize]=t;
            }
        }
    }
}

有序数组去重

给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

示例 1:
给定数组 nums = [1,1,2], 

函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 
你不需要考虑数组中超出新长度后面的元素。
示例 2:

给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
你不需要考虑数组中超出新长度后面的元素。

答案
数组完成排序后,我们可以放置两个指针 ii 和 jj,其中 ii 是慢指针,而 jj 是快指针。只要 nums[i] = nums[j]nums[i]=nums[j],我们就增加 jj 以跳过重复项。

当我们遇到 nums[j] \neq nums[i]nums[j],
 =nums[i] 时,跳过重复项的运行已经结束,因此我们必须把它(nums[j]nums[j])的值复制到 nums[i + 1]nums[i+1]。然后递增 ii,接着我们将再次重复相同的过程,直到 jj 到达数组的末尾为止。
。
int removeDuplicates(int* nums, int numsSize){
    int j = 0;
    nums[j] = nums[0];
    for(int i = 1;i

盛最多水的容器

给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例:

输入:[1,8,6,2,5,4,8,3,7]
输出:49

class Solution {
    public int maxArea(int[] height) {
         int res = 0;
         int i = 0;
         int j = height.length-1;
         while(i

空间复杂度

1.数组的长度
2.递归的深度

你可能感兴趣的:(算法01-数组、链表、跳表的基本实现和特性)