数据结构-栈
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] | |
| */ | 
                    
                
                
            
        
浙公网安备 33010602011771号