小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
例举题目来自leetcode
数组、链表、跳表
数组 Array
- 数组-时间复杂度
- prepend O(1) 向头部或尾部添加
正常情况下数组的prepend的操作的时间复杂度是O(n) 但是 可以进行特殊的优化到O(1)。采用的方式是申请稍大的一些内存空间,然后在数组的最开始预留一部分空间,然后prepend的操作则是把头下标前移一个位置即可。 - append O(1) 任意位置添加
- lookup O(1) 访问任意位置
- insert O(n) 插入
- delete O(n) 删除
链表 Linked List
-
普通链表-时间复杂度
-
prepend O(1) 向头部或尾部添加
-
append O(1) 任意位置添加
-
lookup O(n) 访问任意位置
-
insert O(1) 插入
-
delete O(1) 删除
跳表 Skip List
- 链表元素有序的时候
- 跳表的特点 注意:只能用于元素有序的情况。 所以,跳表(skip list)对标的是平衡树(AVL Tree)和二分查找, 是一种 插入/删除/搜索 都是 O(log n) 的数据结构。1989 年出现。 它最大的优势是原理简单、容易实现、方便扩展、效率更高。因此 在一些热门的项目里用来替代平衡树,如 Redis、LevelDB 等。
- 在跳表中查询任意数据的时间复杂度就是 O(logn)
- 空间复杂度是 O(n)
工程中的应用
- LRU Cache - Linked list
- Redis - Skip List
习题
- 移动零 思路 快慢指针
- 定义指针 i j 遍历整个数组
- 如果发现0 j 指针 记录 0 的位置 在下次的执行时交换 不为0的值 与 为0的值的位置
class Solution{
public void moveZeroes(int[] nums){
for (int i = 0, j = 0; i < nums.length; i++) {
if (nums[i] != 0) {
if (i != j) {
nums[j] = nums[i];
nums[i] = 0;
}
j++;
}
}
}
}
class Solution {
public void moveZeroes(int[] nums) {
for (int i = 0, j = 0; i < nums.length; i++ ) {
if (nums[i] != 0) {
int temp = nums[i];
nums[i] = 0;
nums[j++] = temp;
}
}
}
}
- 盛水最多容器 思路一
- 双层for 循环 时间复杂度 O(n^2)
class Solution{
public int maxArea(int[] height){
int maxArea = 0;
for (int i = 0; i < height.length - 1; i++) {
for (int j = 1; j < height.length; j++) {
int area = (j - i) * Math.min(height[i],height[j]);
maxArea = Math.max(maxArea,area)
}
}
return maxArea;
}
}
2.左右指针夹逼 时间复杂度O(n)
class Solution{
public int maxArea(int[] height){
int max = 0;
for (int i = 0, j = height.length - 1; i < j; ) {
int heights = height[i] < height[j]? height[i++]:height[j--];
int area = (j - i + 1) * heights;
max = Math.max(area,max);
}
return max;
}
}
- 爬楼梯 -- 斐波那契数列
public Solution{
public int climbStairs(int n){
if (n < 3){
return n;
}
int first = 1, second = 2, third = 3;
for (int i = 3; i < n+1; i++) {
third = first + second;
first = second;
second = third;
}
return third;
}
}
- 三数之和 a+b+c = 0
class Solution{
public List<List<Integer>> threeSum ( int[] nums ) {
if ( nums.length < 3 ){
return new ArrayList<>();
}
Arrays.sort(nums);
Set<List<Integer>> set = new HashSet<>();
for ( int i = 0; i < nums.length - 2; i++; ) {
int j = i + 1, k = nums.length - 1;
while ( j < k ) {
int sum = nums[i] + nums[j] + nums[k];
if ( sum == 0 ) set.add( Arrays.asList( nums[i], nums[j++], nums[k--] ) );
else if ( sum > 0 ) k--;
else if ( sum < 0 ) j++;
}
}
return new ArrayList<>( set );
}
}
class Solution {
public List<List<Integer>> threeSum ( int[] nums ) {
List<List<Integer>> res = new ArrayList<>();
if ( nums.length < 3 ) return res;
Arrays.sort( nums );
for ( int i = 0; i < nums.length - 2; i++ ){
if(nums[i] > 0) break;
if(i > 0 && nums[i] == nums[i - 1]) continue;
int j = i + 1, k = nums.length - 1;
while ( j < k ) {
int sum = nums[i] + nums[j] + nums[k];
if ( sum > 0 ) {
while ( j < k && nums[k] == nums[--k] );
}else if( sum < 0 ){
while ( j < k && nums[j] == nums[++j] );
}else {
res.add(new ArrayList<>(Arrays.asList(nums[i], nums[j], nums[k])));
while ( j < k && nums[k] == nums[--k] );
while ( j < k && nums[j] == nums[++j] );
}
}
}
return res;
}
}
var threeSum = function ( nums ) {
let res = [];
if ( nums.length < 3 ) return res;
nums.sort( (a,b) => a - b );
for ( let i = 0; i < nums.length - 2; i++ ){
if(nums[i] > 0) break;
if(i > 0 && nums[i] == nums[i - 1]) continue;
let j = i + 1, k = nums.length - 1;
while ( j < k ) {
let sum = nums[i] + nums[j] + nums[k];
if ( sum > 0 ) {
while ( j < k && nums[k] == nums[--k] );
} else if ( sum < 0 ) {
while ( j < k && nums[j] == nums[++j] );
} else {
res.push( [nums[i], nums[j], nums[k]] );
while ( j < k && nums[k] == nums[--k] );
while ( j < k && nums[j] == nums[++j] );
}
}
}
return res;
}