数据结构-栈

1 找出数组中右边比我小的元素

题目】一个整数数组 A,找到每个元素:右边第一个比我小的下标位置,没有则用 -1 表示。

输入:[5, 2]

输出:[1, -1]

解释:因为元素 5 的右边离我最近且比我小的位置应该是 A[1],最后一个元素 2 右边没有比 2 小的元素,所以应该输出 -1。

接口:int[] findRightSmall(int[] A);

import java.util.*;
public class Example03 {
    public static void main(String[] args) {

        assert(Arrays.equals(new int[]{1,-1}, Solution.findRightSmall(new int[]{5,4})));
        assert(Arrays.equals(new int[]{5, 5, 5, 4, 5, -1, -1}, Solution.findRightSmall(new int[]{1, 2, 4, 9, 4, 0, 5})));
    }
}


class Solution {
    public static int[] findRightSmall(int[] A) {
        Stack<Integer> stack = new Stack<>();
        int[] ans = new int[A.length];
        for (int i = 0; i < A.length;i++){
            int x = A[i];
            while (!stack.isEmpty() && A[stack.peek()] > x) {
                ans[stack.peek()] = i;
                stack.pop();
            }
            stack.push(i);
        }
        while (!stack.isEmpty()){
            ans[stack.peek()] = -1;
            stack.pop();
        }
        return ans;
    }
}

2 右边第一个比我大

/*
 * 题目:给定一个数组,要找到这个数组里面每个元素右边比我大的元素的位置
 * - 注意:是右边第一个比我大的,如果有多个的话
 * - 如果没有,那么用-1表示。
 * 返回:一个数组,表示右边比我大的数的下标位置
 *
 * 输入:[5, 6]
 * 输出:[1, -1]
 * 解释:A[0] = 5,右边比我大的是A[1] = 6, 所以记录为 = 1
 *       A[1] = 6, 右边比我大的元素没有,所以记录为   = -1
 *       所以返回值是[1, -1]
 */

  

package com.demo.stack;

import java.util.Stack;

/**
 * @author Liu Guopeng
 * @date 2021/6/28 下午7:38
 */

// 测试代码

class Verify {
    static int findRightLarge(int[] A, int i) {
        for (int j = i + 1; j < A.length; j++) {
            if (A[j] > A[i]) {
                return j;
            }
        }
        return -1;
    }

    private static void check(int[] A, int[] ans) {
        if (A == null || A.length == 0) {
            return;
        }

        final int N = A.length;
        for (int i = 0; i < N; i++) {
            final int r = ans[i];
            if (r != findRightLarge(A, i)) {
                System.out.println("ERROR");
            }
        }
    }

    public static void DoubleCheck(int[] A) {
        int[] ans = Solution.findRightLarge(A);
        check(A, ans);
    }

    private static int NextInt() {
        final double d = Math.random();
        final int i = (int) (d * 1000);
        return i;
    }

    public static void RandomCheck() {
        for (int i = 0; i < 100; i++) {
            final int len = NextInt() + 1;
            int[] A = new int[len];
            for (int j = 0; j < len; j++) {
                A[j] = NextInt();
            }
            DoubleCheck(A);
        }
    }
}
public class Practice03A {
    public static void main(String[] args) {
        Verify.DoubleCheck(new int[]{5,4});
        Verify.DoubleCheck(new int[] { 1, 2, 4, 9, 4, 0, 5 });
        Verify.RandomCheck();
    }
}


class Solution {
    // 当我们要找右边比我大的元素的时候,需要用递减栈
    public static int[] findRightLarge(int[] A) {
        Stack<Integer> stack = new Stack<>();
        int[] ans = new int[A.length];
        for (int i = 0; i < A.length; i++){
            int x = A[i];
            while (!stack.isEmpty() && A[stack.peek()] < x){
                ans[stack.peek()] = i;
                stack.pop();
            }
            stack.push(i);
        }
        while (!stack.isEmpty()){
            ans[stack.peek()] = -1;
            stack.pop();
        }
        return ans;
    }
}

3 左边第一个比我小

/**
 * 题目:给定一个数组,要找到这个数组里面每个元素左边比我小的元素的位置
 * - 注意:是左边第一个比我小的,如果有多个的话
 * - 如果没有,那么用-1表示。
 *
 * 返回:一个数组,表示左边比我小的数的下标位置
 *
 * 输入:[5, 6]
 * 输出:[-1, 0]
 * 解释:A[0] = 5,左边比我小的元素没有, 所以记录为 = -1
 *       A[1] = 6, 左边比我小的元素为A[0] = 5,所以记录为   = 0
 *       所以返回值是[-1, 0]
 */

  

package com.demo.stack;

import java.util.Stack;

public class Practice03B {
    public static void main(String[] args) {
        Solution.findLeftSmall(new int[] { 1, 2, 4, 9, 4, 0, 5 });
        Verify.DoubleCheck(new int[] { 5, 4 });
        Verify.DoubleCheck(new int[] { 1, 2, 4, 9, 4, 0, 5 });


        Verify.RandomCheck();

    }
}

class Solution {
    // 当我们要找左边比我小的元素的时候,需要用递增栈
    public static int[] findLeftSmall(int[] A) {
        if (A == null || A.length == 0) {
            return new int[0];
        }

        // 结果数组
        int[] ans = new int[A.length];
        // 注意,栈中的元素记录的是下标
        Stack<Integer> t = new Stack<>();

        // 注意这里的遍历方向发生了变化,因为我们是要找到左边比我小的元素的位置
        for (int i = A.length - 1; i >= 0; i--) {
            final int x = A[i];
            // 每个元素都遍历栈中的元素完成消除动作
            // 这里是递减栈
            // 如果发现进来的元素x与栈中元素相比
            // 如果大于栈中的元素,那么要把栈中的元素弹出去
            while (!t.empty() && A[t.peek()] > x) {
                // 消除的时候,记录一下被谁消除了
                ans[t.peek()] = i;
                // 消除时候,值更大的需要从栈中消失
                t.pop();
            }
            // 剩下的入栈
            t.push(i);
        }
        // 栈中剩下的元素,由于没有人能消除他们,因此,只能将结果设置为-1。
        while (!t.empty()) {
            ans[t.peek()] = -1;
            t.pop();
        }

        return ans;
    }
}

// 测试代码

class Verify {
    private static int findLeftSmall(int[] A, int i) {
        for (int j = i - 1; j >= 0; j--) {
            if (A[j] < A[i]) {
                return j;
            }
        }
        return -1;
    }

    private static void check(int[] A, int[] ans) {
        if (A == null || A.length == 0) {
            return;
        }

        final int N = A.length;
        for (int i = 0; i < N; i++) {
            final int r = ans[i];
            if (r != findLeftSmall(A, i)) {
                System.out.println("ERROR");
            }
        }
    }

    public static void DoubleCheck(int[] A) {
        int[] ans = Solution.findLeftSmall(A);
        check(A, ans);
    }

    private static int NextInt() {
        final double d = Math.random();
        final int i = (int) (d * 1000);
        return i;
    }

    public static void RandomCheck() {
        for (int i = 0; i < 100; i++) {
            final int len = NextInt() + 1;
            int[] A = new int[len];
            for (int j = 0; j < len; j++) {
                A[j] = NextInt();
            }

            DoubleCheck(A);
        }
    }
}

 4  左边第一个比我大

/*
 * 题目:给定一个数组,要找到这个数组里面每个元素左边比我大的元素的位置
 * - 注意:是左边第一个比我大的,如果有多个的话
 * - 如果没有,那么用-1表示。
 *
 * 返回:一个数组,表示左边比我大的数的下标位置
 *
 * 输入:[5, 6]
 * 输出:[-1, -1]
 * 解释:A[0] = 5,左边比我大的元素没有, 所以记录为 = -1
 *       A[1] = 6, 左边比我大的元素为没有,所以记录为 = -1
 *       所以返回值是[-1, -1]
 */

  

package com.demo.stack;

import java.util.Stack;


class Solution {
    // 当我们要找左边比我大的元素的时候,需要用递减栈
    public static int[] findLeftLarge(int[] A) {
        if (A == null || A.length == 0) {
            return new int[0];
        }

        // 结果数组
        int[] ans = new int[A.length];
        // 注意,栈中的元素记录的是下标
        Stack<Integer> t = new Stack<>();

        // 注意这里的遍历方向发生了变化,因为我们是要找到左边比我大的元素的位置
        for (int i = A.length - 1; i >= 0; i--) {
            final int x = A[i];
            // 每个元素都遍历栈中的元素完成消除动作
            // 这里是递减栈
            // 如果发现进来的元素x与栈中元素相比
            // 如果大于栈中的元素,那么要把栈中的元素弹出去
            while (!t.empty() && A[t.peek()] < x) {
                // 消除的时候,记录一下被谁消除了
                ans[t.peek()] = i;
                // 消除时候,值更大的需要从栈中消失
                t.pop();
            }
            // 剩下的入栈
            t.push(i);
        }
        // 栈中剩下的元素,由于没有人能消除他们,因此,只能将结果设置为-1。
        while (!t.empty()) {
            ans[t.peek()] = -1;
            t.pop();
        }

        return ans;
    }
}

// 测试代码

class Verify {
    private static int findLeftLarge(int[] A, int i) {
        for (int j = i - 1; j >= 0; j--) {
            if (A[j] > A[i]) {
                return j;
            }
        }
        return -1;
    }

    private static void check(int[] A, int[] ans) {
        if (A == null || A.length == 0) {
            return;
        }

        final int N = A.length;
        for (int i = 0; i < N; i++) {
            final int r = ans[i];
            if (r != findLeftLarge(A, i)) {
                System.out.println("ERROR");
            }
        }
    }

    public static void DoubleCheck(int[] A) {
        int[] ans = Solution.findLeftLarge(A);
        check(A, ans);
    }

    private static int NextInt() {
        final double d = Math.random();
        final int i = (int) (d * 1000);
        return i;
    }

    public static void RandomCheck() {
        for (int i = 0; i < 100; i++) {
            final int len = NextInt() + 1;
            int[] A = new int[len];
            for (int j = 0; j < len; j++) {
                A[j] = NextInt();
            }

            DoubleCheck(A);
        }
    }
}

class Practice03C {
    public static void main(String[] args) {
        Verify.DoubleCheck(new int[] { 5, 4 });
        Verify.DoubleCheck(new int[] { 1, 2, 4, 9, 4, 0, 5 });

        Verify.RandomCheck();

    }
}

 

 5 字典序最小的 k 个数的子序列

【题目】给定一个正整数数组和 k,要求依次取出 k 个数,输出其中数组的一个子序列,需要满足:1. 长度为 k;2.字典序最小。

输入:nums = [3,5,2,6], k = 2
输出:[2,6]

解释:在所有可能的解:{[3,5], [3,2], [3,6], [5,2], [5,6], [2,6]} 中,[2,6] 字典序最小。

在英文字典中,排列单词的顺序是先按照第一个字母以升序排列(即a、b、c……z 的顺序);如果第一个字母一样,那么比较第二个、第三个乃至后面的字母。如果比到最后两个单词不一样长(比如,sigh 和 sight),那么把短者排在前

复制代码
接口:int[] findSmallSeq(int[] A, int k);

package com.demo.stack;

import java.util.Arrays;
import java.util.Stack;

class Solution {
    public static int[] findSmallSeq(int[] nums, int k) {
        Stack<Integer> t = new Stack<>();
        int[] ans = new int[k];
        for (int i = 0; i < nums.length;i++){
            int x = nums[i];
            int left = nums.length - i;
            while(!t.isEmpty() && (left + t.size()) > k && t.peek() >x){
                t.pop();
            }
            t.push(x);
        }
        while (!t.isEmpty() && t.size() > k){
            t.pop();
        }
        for (int i = k- 1; i >= 0;i--){
            ans[i] = t.pop();
        }
        return ans;

    }
}

class Example04 {
    public static void main(String[] args) {
//        Solution.findSmallSeq(new int[]{9,2,4,5,1,2,6,3,100,4}, 3);
        assert(Arrays.equals(new int[]{1,2,3}, Solution.findSmallSeq(new int[]{9,2,4,5,1,2,6,3,100,4}, 3)));
        assert(Arrays.equals(new int[]{1,2}, Solution.findSmallSeq(new int[]{9,2,4,5,1,2,6,3,100,4}, 2)));
        assert(Arrays.equals(new int[]{1}, Solution.findSmallSeq(new int[]{9,2,4,5,1,2,6,3,100,4}, 1)));
        assert(Arrays.equals(new int[]{1}, Solution.findSmallSeq(new int[]{1,1,1,1,1}, 1)));
    }
}

 

 

 

 

 

 

 

 

/*
  * 题目:给定一个数组,要找到这个数组里面每个元素右边比我大的元素的位置
  * - 注意:是右边第一个比我大的,如果有多个的话
  * - 如果没有,那么用-1表示。
  * 返回:一个数组,表示右边比我大的数的下标位置
  *
  * 输入:[5, 6]
  * 输出:[1, -1]
  * 解释:A[0] = 5,右边比我大的是A[1] = 6, 所以记录为 = 1
  * A[1] = 6, 右边比我大的元素没有,所以记录为 = -1
  * 所以返回值是[1, -1]
  */

 

posted @ 2021-06-28 14:52  润肺  阅读(67)  评论(0)    收藏  举报