zoukankan      html  css  js  c++  java
  • 剑指offer(五,六),用两个栈实现队列,旋转数组的最小数字

    题目描述

    用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

     一个栈就是把队列反过来,那再来一个栈push进第一个栈就“正”过来了。
    第一个栈就是存下反过来的序列。
     每次push进一个数,要先判断stack2“正”序列是否为空,不为空要还原“反序列”,还要stack1 push进所有的stack2。
     每次pop一个数,把stack1全部push进来,就变成了“正序列”,return stack2的pop即可。
     但是想想,有个小优化,push的时候不用在stack1还原反序列,直接push进stack1,这样在pop的时候判断stack2是否为空,不为空,直接pop,这样把早先“入队列”的pop完,再push stack1的。加了一个判断,简化了第一个栈的操作。
     任何时候pop要判断是否还有元素。

    import java.util.Stack;
     
    public class Solution {
        Stack<Integer> stack1 = new Stack<Integer>();
        Stack<Integer> stack2 = new Stack<Integer>();
         
        public void push(int node) {
            stack1.push(node);
        }
         
        public int pop() {
            if(stack1.empty()&&stack2.empty()){
                throw new RuntimeException("Queue is empty!");
            }
            if(stack2.empty()){
                while(!stack1.empty()){
                    stack2.push(stack1.pop());
                }
            }
            return stack2.pop();
        }
    }
    
    import java.util.Stack;
    
    class Solution {
        Stack<Integer> stack1 = new Stack<Integer>();
        Stack<Integer> stack2 = new Stack<Integer>();
    
        public void push(int node) {
            while(!stack2.empty()){
                stack1.push(stack2.pop());
            }
            stack1.push(node);
        }
    
        public int pop() {
            if(stack1.empty()&&stack2.empty()){
                throw new RuntimeException("Queue is empty!");
            }
            while(!stack1.empty()) {
                stack2.push(stack1.pop());
            }
            return stack2.pop();
        }
    }
    
    class Main {
    
    }
    

    然后又用我大JS做了一遍,我大JS,每个数组就是一个栈,233,直接push和pop方法。
    注意js对pop() 时两个栈为空的处理。 js 是默认返回 undefined ,其他静态语言一般是报异常。

    var stack1 = [],
        stack2 = [];
    function push(node) {
        stack1.push(node);
    }
    function pop() {
        if (!stack2.length&&!stack2.length) {
    	    //处理
        }
        if (!stack2.length) {
            while (stack1.length) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }
    
    /*
    // 测试
    var arr = [];
    arr.push(1)
    arr.push(2)
    arr.push(3)
    console.log(arr);
    console.log(arr.pop());*/
    
    

    题目描述

    把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

     普通查找时间复杂度为n,出在这里肯定是要找优化的。明显是二分,二分的条件,边界和判断就是关键。
     序列保证是旋转过的,如果长度是2,直接返回右边的。我们现在就找这个边界值,未旋转的非递减序列左边肯定小于右边。现在我们就不断缩小这个边界存在的区间。
     中间元素大于第一个元素,则这个中间元素处于从left开始到中间元素只有一个的序列当中,此时最小元素位于中间元素的后面。
     中间元素小于第一个元素,则这个中间元素“非正常”,左面元素到这个元素之间包含了两个序列,最小的数肯定在中间元素前面。
     我这个二分,是留存mid的,所以最后肯定是分到只剩下两个数,且这两个数一定是旋转的,那么右边就是最小的数。
     eg:
     3 1 2,返回3 1,因为缩小的是“旋转的区间的长度”
     3 4 1,返回4 1,最终的都是右边最小,返回即可。
     另外的最坏情况就是有相同的元素,array[l] == array[r] && array[l] == array[mid],不能用条件来缩小查找区间,这时候的序列肯定只有两种数,只能顺序查找,找到第一个小的,直接break即可。

    import java.util.ArrayList;
    public class Solution {
        public int minNumberInRotateArray(int [] array) {
            int len = array.length;
            if(len==0)
                return 0;
            int l = 0;
            int r = len-1;
            int mid = 0;
            while(r-l!=1) {
                mid = (l+r)/2;
                if(array[l] == array[r] && array[l] == array[mid]){
                    return OtherSolve(array,l,r);
                }
                //当中间比第一个元素大时,最小数在右边,因为右边的最小序列整体都是小于左边的大序列
                if(array[mid]>=array[l])
                    l = mid;
                //当中间比第一个元素小时,最小数在左边,最小序列的任何一个数整体都是小于左边的大序列
                else if(array[mid]<=array[l]) {
                    r = mid;
                }
            }
            return array[r];
        }
         int OtherSolve(int array[],int l,int r){
            int t = array[l];
            for(int i = l+1; i<=r; i++) {
                if(array[i]<t)
                    t = array[i];
            }
            return t;
        }
    }
    
  • 相关阅读:
    go语言——strings和strconv
    go语言——map
    Manjaro配置
    go语言——数组和切片
    go语言——随机数
    go——选择和循环
    go语言——输入输出
    java动态代理实现--基于子类的动态代理
    java动态代理实现--基于接口的动态代理
    spring依赖注入
  • 原文地址:https://www.cnblogs.com/zhangmingzhao/p/8152257.html
Copyright © 2011-2022 走看看