题目一:
请编写一个程序,按升序对栈进行排序(即最大元素位于栈顶),要求最多只能使用一个额外的栈存放临时数据,但不得将元素复制到别的数据结构中。给定一个int[] numbers,其中第一个元素为栈顶,请返回排序后的栈。请注意这是一个栈,意味着排序过程中你只能访问到第一个元素。
测试样例:[1,2,3,4,5] 返回:[5,4,3,2,1]。
思路:这道题目很考验逻辑思维能力。将要排序的栈记为source,申请的辅助栈记为target。在source上执行pop操作,弹出的元素记为cru。 如果cru大于或等于target的栈顶元素,则将cru直接压入target。 如果cru小于target的栈顶元素,则将target的元素逐一弹出,逐一压入source,直到cru大于或等于target的栈顶元素,再将cru压入target。一直执行以上操作,直到source中的全部元素压入到target,最后返回target,完成排序。
1 import java.util.Stack; 2 3 public class StackSort { 4 public static void main(String[] args) { 5 StackSort obj = new StackSort(); 6 obj.twoStacksSort(new int[] { 8, 2, 3, 4, 5 }); // 输出 8 5 4 3 2 7 } 8 9 public void twoStacksSort(int[] numbers) { 10 // 初始化原始栈 11 Stack<Integer> source = new Stack<>(); 12 for (int i = numbers.length - 1; i >= 0; i--) { 13 source.push(numbers[i]); 14 } 15 16 Stack<Integer> target = twoStacksSort(source); 17 while (!target.isEmpty()) { 18 System.out.println(target.pop()); 19 } 20 } 21 22 public Stack<Integer> twoStacksSort(Stack<Integer> source) { 23 24 Stack<Integer> target = new Stack<>(); 25 sortToTarget(source, target); 26 27 return target; 28 } 29 30 private void sortToTarget(Stack<Integer> source, Stack<Integer> target) { 31 while (!source.empty()) { 32 int v1 = source.pop(); // 揭开盖子 33 if (target.empty()) { 34 target.push(v1); 35 } else { 36 int v2 = target.peek(); 37 if (v1 >= v2) { // 盖子大,直接放入 38 target.push(v1); 39 } else { // 盖子小,把大的先回收 40 source.push(target.pop()); 41 // 直到有盖子的容身之所 42 while (!target.empty() && v1 < target.peek()) { 43 source.push(target.pop()); 44 } 45 target.push(v1); 46 } 47 } 48 } 49 } 50 }
题目二:
猫狗收容所:有家动物收容所只收留猫和狗,但有特殊的收养规则,收养人有两种收养方式,第一种为直接收养所有动物中最早进入收容所的,第二种为选择收养的动物类型(猫或狗),并收养该种动物中最早进入收容所的。给定一个操作序列int[][2] 代表所有事件。若第一个元素为1,则代表有动物进入收容所,第二个元素为动物的编号,正数代表狗,负数代表猫;若第一个元素为2,则代表有人收养动物,第二个元素若为0,则采取第一种收养方式(最早),若为1,则指定收养狗,若为-1则指定收养猫。请按顺序返回收养的序列。若出现不合法的操作,即没有可以符合领养要求的动物,则将这次领养操作忽略。
测试样例:[1, 1], [1, -1], [1, 0], [1, -5], [2, 0], [2, -1], [2, 0; 返回 [1, -1, -5]。
思路:可以根据题目要求画出下图所示的树。
从题目中我们可以知道需要按照时间顺序求解出收养动物编号的序列,这里先进来的动物是最早可能被收养的,所以我们可以使用队列这种数据结构来存储其中的数据。我们可以使用两个队列,一个是猫的队列,一个是狗的队列这样可以方便我们入队和出队。这样的话当出队的时候就有一个问题,当第二个元素为0的时候就不知道该取谁了。我们可以利用一个全局变量来创建一个类似于时间点的东西,然后根据这个全局变量的大小判断谁先被收留,然后就可以选择谁先被收养了。
1 import java.util.ArrayList; 2 import java.util.LinkedList; 3 import java.util.Queue; 4 5 public class CatDogAsylum { 6 private static class Animal { 7 int type; 8 int time; 9 static int timeline;// 全局变量,记录动物的时间点 10 11 public Animal(int typeNumber) { 12 this.type = typeNumber; 13 this.time = timeline++; 14 } 15 } 16 17 public ArrayList<Integer> asylum(int[][] ope) { 18 ArrayList<Integer> res = new ArrayList<>(); 19 20 Queue<Animal> cats = new LinkedList<>(); 21 Queue<Animal> dogs = new LinkedList<>(); 22 for (int[] row : ope) { 23 int op = row[0]; 24 int typeNumber = row[1]; 25 if (op == 1) {// 增加 26 if (typeNumber > 0) { 27 dogs.add(new Animal(typeNumber)); 28 } 29 if (typeNumber < 0) { 30 cats.add(new Animal(typeNumber)); 31 } 32 } else if (op == 2) {// 减少 33 if (typeNumber == 0) {// 从两个队列中选timeline最小的 34 if ((!dogs.isEmpty()) && (cats.isEmpty() || dogs.peek().time < cats.peek().time)) { 35 res.add(dogs.poll().type); 36 } 37 if ((!cats.isEmpty()) && (dogs.isEmpty() || dogs.peek().time > cats.peek().time)) { 38 res.add(cats.poll().type); 39 } 40 } else {// 用户指定了类型 41 if (typeNumber == 1 && !dogs.isEmpty()) { 42 res.add(dogs.poll().type); 43 } 44 if (typeNumber == -1 && !cats.isEmpty()) { 45 res.add(cats.poll().type); 46 } 47 } 48 } else { 49 break; 50 } 51 } 52 return res; 53 } 54 55 public static void main(String[] args) { 56 CatDogAsylum obj = new CatDogAsylum(); 57 int[][] data = { { 1, 1 }, { 1, -1 }, { 1, 0 }, { 1, -5 }, { 2, 0 }, { 2, -1 }, { 2, 0 } }; 58 // 输出 [1, -1, -5] 59 System.out.println(obj.asylum(data)); 60 } 61 }