【91 算法-基础篇】01.数组,栈,队列

例题一:66. 加一

在这里插入图片描述

class Solution {
    public int[] plusOne(int[] digits) {
            int n = digits.length;
            for(int i = n-1; i > -1; i--){
                    if(digits[i] == 9)
                            digits[i] = 0;
                    else{
                            digits[i] += 1;
                            return digits;
                    }
            }
            digits = new int[n+1];
            digits[0] = 1;
            return digits;
    }
}

例题二:75.颜色分类

在这里插入图片描述

思路

采用三个指针,一个指针curr从0开始遍历数组,一个指针p0从0开始指向待交换成0的位置,一个指针p2从nums.length-1开始指向待交换成2的位置。当curr遇到0时,和p0位置的元素交换,并且p0和curr都向后移动一位;当curr遇到2时,和p2位置的元素交换,但此时只向前移动p2,curr不动,这是因为从p2交换来的元素可能是0、1、2任意一个数,而从p0交换来的元素只可能是1;当curr遇到1时,继续向后移动。

代码

class Solution {
    public void sortColors(int[] nums) {
            int p0 = 0, p2 = nums.length - 1, curr = 0;
            while(curr <= p2){
                    if(nums[curr] == 0){
                            swap(curr, p0, nums);
                            p0++;
                            curr++;
                    }
                    else if(nums[curr] == 2){
                            swap(curr, p2, nums);
                            p2--;
                    }
                    else
                            curr++;
            }
    }
        private void swap(int i, int j, int[] nums){
                int temp = nums[i];
                nums[i] = nums[j];
                nums[j] = temp;
        }
}

例题三:1381. 设计一个支持增量操作的栈

请你设计一个支持下述操作的栈。

实现自定义栈类 CustomStack :

CustomStack(int maxSize):用 maxSize 初始化对象,maxSize 是栈中最多能容纳的元素数量,栈在增长到 maxSize 之后则不支持 push 操作。
void push(int x):如果栈还未增长到 maxSize ,就将 x 添加到栈顶。
int pop():弹出栈顶元素,并返回栈顶的值,或栈为空时返回 -1 。
void inc(int k, int val):栈底的 k 个元素的值都增加 val 。如果栈中元素总数小于 k ,则栈中的所有元素都增加 val 。

示例:

输入:
[“CustomStack”,“push”,“push”,“pop”,“push”,“push”,“push”,“increment”,“increment”,“pop”,“pop”,“pop”,“pop”]
[[3],[1],[2],[],[2],[3],[4],[5,100],[2,100],[],[],[],[]]
输出:
[null,null,null,2,null,null,null,null,null,103,202,201,-1]
解释:
CustomStack customStack = new CustomStack(3); // 栈是空的 []
customStack.push(1); // 栈变为 [1]
customStack.push(2); // 栈变为 [1, 2]
customStack.pop(); // 返回 2 --> 返回栈顶值 2,栈变为 [1]
customStack.push(2); // 栈变为 [1, 2]
customStack.push(3); // 栈变为 [1, 2, 3]
customStack.push(4); // 栈仍然是 [1, 2, 3],不能添加其他元素使栈大小变为 4
customStack.increment(5, 100); // 栈变为 [101, 102, 103]
customStack.increment(2, 100); // 栈变为 [201, 202, 103]
customStack.pop(); // 返回 103 --> 返回栈顶值 103,栈变为 [201, 202]
customStack.pop(); // 返回 202 --> 返回栈顶值 202,栈变为 [201]
customStack.pop(); // 返回 201 --> 返回栈顶值 201,栈变为 []
customStack.pop(); // 返回 -1 --> 栈为空,返回 -1

提示:

1 <= maxSize <= 1000
1 <= x <= 1000
1 <= k <= 1000
0 <= val <= 100
每种方法 increment,push 以及 pop 分别最多调用 1000 次

思路

主要说一下increment()函数,最直接的一种方法是直接对栈中满足要求的元素重新赋值,这种方法的时间复杂度为 O ( m i n ( k , t o p ) ) O(min(k, top)) O(min(k,top))。为了将时间复杂度降为 O ( 1 ) O(1) O(1),我们可以用空间换时间,具体做法是维护一个数组increments[],长度为maxSize,将增量赋值到increments[min(k-1, top)]处,当pop()时将arr[top]+increments[top]输出。

代码

class CustomStack {
        private int[] arr;
        private int maxSize;
        private int top;
        private int[] increments;

    public CustomStack(int maxSize) {
            this.maxSize = maxSize;
            arr = new int[maxSize];
            increments = new int[maxSize];
            top = -1;
    }
    
    public void push(int x) {
        if(!isFull()){
                arr[++top] = x;
        }
    }
    
    public int pop() {
            if(!isEmpty()){
                    int val = arr[top] + increments[top];
                    top--;
                    if(!isEmpty())
                            increments[top] += increments[top+1];
                    increments[top+1] = 0;
                    return val;
            }
            else
                    return -1;
    }
    
    public void increment(int k, int val) {
            if(k > 0 && !isEmpty()){
                int index = k-1 < top ? k-1 : top;
                increments[index] += val;
            }
    }
        public boolean isEmpty(){
                return top == -1;
        }
        public boolean isFull(){
                return top == maxSize - 1;
        }
}

复杂度

时间复杂度:全部都是 O ( 1 ) O(1) O(1)
空间复杂度:我们维护了一个大小为 maxSize 的数组,因此平均到每次的空间复杂度为 O ( m a x S i z e / N ) O(maxSize / N) O(maxSize/N),其中 N 为操作数。
我们还可以用一个动态数组实现increments[],这样空间复杂度就可以降低到 O ( m a x S i z e / t o p ) O(maxSize / top) O(maxSize/top),top为栈的当前长度

例题四:394. 字符串解码

在这里插入图片描述

思路

运用了栈,将字符依次入栈,遇到’]'则弹出括号之间的内容,并根据‘[’之前的数字进行处理,处理后的字符串入栈,直至原字符串全部入栈。

代码

class Solution {
    public String decodeString(String s) {
        Deque<String> stack = new ArrayDeque<>();
        for(int i = 0; i < s.length(); i++){
            char c = s.charAt(i);
            if(c == ']'){
                String str = "";
                while(!stack.peek().equals("[")){
                    str = stack.pop() + str;
                }
                stack.pop();
                String numString = "";
                while(stack.peek() != null && Character.isDigit(stack.peek().charAt(0))){
                    numString = stack.pop() + numString;
                }
                int num = Integer.parseInt(numString);
                String temp = str;
                for(int j = 0; j < num - 1; j++){
                    str += temp;
                }
                stack.push(str);
            }else{
                stack.push(String.valueOf(c));
            }
        }
        String res = "";
        while(!stack.isEmpty()){
            res = stack.pop() + res;
        }
        return res;
    }
}

例题五:232. 用栈实现队列

在这里插入图片描述

思路

用两个栈来实现队列,push的数据放入stack1中,pop或peek时先看stack2,若stack2为空,则将stack1中的数据依次放入stack2中,再从stack2中pop或peek。

代码

class MyQueue {

        Deque<Integer> stack1;
        Deque<Integer> stack2;
    /** Initialize your data structure here. */
    public MyQueue() {
            stack1 = new ArrayDeque<Integer>();
            stack2 = new ArrayDeque<Integer>();
    }
    
    /** Push element x to the back of queue. */
    public void push(int x) {
        stack1.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    public int pop() {
        if(!stack2.isEmpty()){
                return stack2.pop();
        }else if(!stack1.isEmpty()){
                while(!stack1.isEmpty()){
                        stack2.push(stack1.pop());
                }
                return stack2.pop();
        }
            return -1;
    }
    
    /** Get the front element. */
    public int peek() {
        if(!stack2.isEmpty()){
                return stack2.peek();
        }else if(!stack1.isEmpty()){
                while(!stack1.isEmpty()){
                        stack2.push(stack1.pop());
                }
                return stack2.peek();
        }
            return -1;
    }
    
    /** Returns whether the queue is empty. */
    public boolean empty() {
        return stack1.isEmpty() && stack2.isEmpty();
    }
}

复杂度

时间复杂度为 O ( n ) O(n) O(n),但对于多次操作来说,因为不是每一次pop或peek都要将stack1中的数据放入stack2,所以平均下来也可以看做 O ( 1 ) O(1) O(1)
空间复杂度为 O ( n ) O(n) O(n)。n为stack1和stack2的size之和。

例题六:380. 常数时间插入、删除和获取随机元素

在这里插入图片描述

思路

采用数组和哈希表想结合的方法,哈希表存储数组中的数和它对应的数组下标。

  • 插入:首先要查询待插入的数是否存在,这时用哈希表来查,时间复杂度为 O ( 1 ) O(1) O(1),若不存在,直接将数插入到数组的末尾和哈希表中,时间复杂度都为 O ( 1 ) O(1) O(1)
  • 删除:首先要查询待删除的数是否存在,同上。若存在,通过哈希表找到它的数组下标,再讲数组中的这个数和数组最后一个数交换,然后删除数组中最后一个数最后再把哈希表中的数删除,这两种删除操作时间复杂度都为 O ( 1 ) O(1) O(1)
  • 随机获取:通过数组下标的方式获取元素,时间复杂度为 O ( 1 ) O(1) O(1)

代码

class RandomizedSet {

    /** Initialize your data structure here. */
        Map<Integer, Integer> map;
        ArrayList<Integer> arr;
        Random random;
    public RandomizedSet() {
        map = new HashMap<Integer, Integer>();
            arr = new ArrayList<Integer>();
            random = new Random();
    }
    
    /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
    public boolean insert(int val) {
            if(map.containsKey(val)){
                    return false;
            }
            else{
                    map.put(val, arr.size());
                    arr.add(val);
                    return true;
            }
    }
    
    /** Removes a value from the set. Returns true if the set contained the specified element. */
    public boolean remove(int val) {
        if(map.containsKey(val)){
                int index = map.get(val);
                int temp = arr.get(arr.size()-1);
                arr.set(index, temp);
                map.put(temp, index);
                map.remove(val);
                arr.remove(arr.size()-1);
                return true;
        }else{
                return false;
        }
    }
    
    /** Get a random element from the set. */
    public int getRandom() {
        return arr.get(random.nextInt(arr.size()));
    }
}

复杂度

  • 时间复杂度为 O ( 1 ) O(1) O(1)
  • 空间复杂度为 O ( N ) O(N) O(N),N为存储的元素个数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值