`
QING____
  • 浏览: 2250590 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

算法编程(三)

 
阅读更多

一、请使用栈,设计一个数据结构,它具有栈的“先进后出”的特性,同时还可以获取栈中的最小值,要求此数据结构的pop、push、min方法的复杂度均为O(1)

    这个题,最大的问题就在min方法上,如果不使用其他的辅助数据结构,是无法满足min方法的设计要求,即使使用一个临时变量保存当前的最小值(这种情况下,如果最小是被pop,就断片了。。)。所以我们的注意力就集中在:怎们能让一个栈是有序的?其实让栈内数据有序,使用排序的思路肯定是不行的,但是我们能够维持“最小值”的连续性就可以。看看如下的设计思路:

使用2个栈来设计这个数据结构,分别为数据栈和辅助栈
数据栈用来保存push的数据
辅助栈用来保存“最小值”的连续性:

栈底<--------->栈顶
1)添加3
数据栈:3
辅助栈:3,3为最小值
2)添加4
数据栈: 3 4
辅助栈: 3 3
因为4 > 3,为了保持“最小值”连续性,我们在4对应的辅助栈的位置上仍然添加3。
3)添加2
数据栈: 3 4 2
辅助栈: 3 3 2
因为3 > 2,最小值变了,所以讲新的最小值入栈。

如上所述,那么min方法,只需要从辅助栈中peek栈顶的元素值就行了。
当数据栈中pop元素时,也将辅助栈中对应位置的元素移除。

 

    代码样例如下:

static class MinStack {
    Stack<Integer> data = new Stack<>();
    Stack<Integer> helper = new Stack<>();

    synchronized void push(Integer value) {
        data.push(value);
        int min = value;
        if(!helper.isEmpty()) {
            int current = helper.peek();
            if(current <= value) {
                min = current;
            }
        }
        helper.push(min);
    }

    Integer min() {
        if(helper.isEmpty()) {
            return null;
        }
        return helper.peek();
    }

    synchronized void pop() {
        if(data.isEmpty()) {
            return;
        }
        data.pop();
        helper.pop();
    }
}

    

二、请编写一个算法用于判定:序列B为序列A作为栈时可能的弹出顺序(A中的数字不会重复)

    听到题目,第一感觉就是:听不懂!

    先描述一下:假如有序列A为[1,2,3,4,5],它作为栈时由1开始依次入栈,序列B为[5,4,3,2,1]是A作为栈时的一个弹出顺序。但是序列A在没有完全入栈时也可以弹出,比如[1,2,3,4]先入栈,然后弹出4,然后再将5入栈,那么其弹出序列就是[4,5,3,2,1]。因为A入栈和出栈的时机可以任意,所以它的出栈序列可能会有多种,请你判定一个给定的序列是否为A的一个出栈顺序。

    实话说,看到这个题,我也没有思路...如下为分析过程,突破口就是要用一个辅助栈来保存A。

将A保存在数据栈,B使用一个辅助栈
A:1 2 3 4 5
B:4 5 3 2 1 (假设序列)

1)
遍历A和B,以B作为判断基准
2)
在B中第一个元素为4,因为A中1、2、3均不等于4,直到遇到4
则将它们都添加到数据栈
数据栈: 1 2 3 
3)此时A与B都遇到4,我们认为是一次弹出(或者同时入栈,然后弹出)
4)B继续遍历,此时为5
判断,5是否与数据栈的栈顶一样,如果不一样,则遍历A的下一个元素。
5)此时A与B都遇到5,我们认为是一次弹出。
6)A序列遍历结束,只能根据数据栈作为判定。
7)B继续遍历,此时为3,从数据栈中弹出栈顶,比较是否也为3,如果是继续
8)重复7,直到不相等(返回false)或者数据栈全部弹出(返回true)。

 

    解题思路总结:从B中确定弹出元素,比如a,如果辅助栈的栈顶刚还是a,则弹出,否则遍历A序列找到a,在a之前的元素全部添加到辅助栈中;如果所有的元素都查找完仍没有找到a,则认为判读失败。

 

    代码样例:

public static void main(String[] args) {
    int[] source = {1,2,3,4,5};
    int[] target = {3,5,4,2,1};
    System.out.println(check(source,target));
}

public static boolean check(int[] source,int[] target) {
    if(source.length == 0 || target.length == 0) {
        return false;
    }
    if(source.length != target.length) {
        return false;
    }
    int length = source.length;
    Stack<Integer> data = new Stack<>();
    int di = 0;//数据序列的索引位置
    for(int i = 0; i < length; i ++) {
        int item = target[i];
        //入栈完毕
        if(di == length) {
            if(data.isEmpty()) {
                return false;
            }
            int top = data.pop();
            if(top == item) {
                continue;
            }else {
                return false;
            }
        }
        while (di < length) {
            int current = source[di];
            if(item == current) {
                di++;
                break;
            } else if(data.isEmpty()){
                data.push(current);
                di++;
            } else {
                int top = data.peek();
                if(top == item) {
                    data.pop();
                    break;
                }else {
                    data.push(current);
                    di++;
                }
            }
        }
    }
    return true;
}

 

三、使用广度优先的方式遍历二叉树,并逐层打印节点值

    广度优先,就是按照二叉树的level,逐级遍历。如果你有过此方面的算法经验,其实这个题非常简单。如果你喜欢钻牛角尖,估计这题不好办!钻牛角尖的思路就是:递归、遍历、数组等等。

    推演思路:

假如输入二叉树,树的结构如下:
           8
          /\
      6        10
     /\        /\
    5  7      9  11

当前节点          队列
8               6,10
6               10,5,7
10              5,7,9,11
5               7,9,11
7               9,11
9               11
11              空

要求打印结果:8 6 10 5 7 9 11

 

    突破口已经有了,就是使用一个队列来保存即将参与打印的节点。太有才了,此后大家需要记住,广度遍历二叉树时要使用队列!!代码样例如下:

static class BinaryTree {
    BinaryTreeNode root;
}
static class BinaryTreeNode {
    BinaryTreeNode left;
    BinaryTreeNode right;
    int value;
}

public static void print(BinaryTree tree) {
    if(tree == null) {
        return;
    }
    BinaryTreeNode root = tree.root;
    if(root == null) {
        return;
    }
    Queue<BinaryTreeNode> data = new LinkedList<>();
    data.add(root);
    while (!data.isEmpty()) {
        BinaryTreeNode current = data.poll();
        System.out.print(current.value + ",");
        BinaryTreeNode left = current.left;
        if(left != null) {
            data.add(left);
        }
        BinaryTreeNode right = current.right;
        if(right != null) {
            data.add(right);
        }
    }
}

 

    我们还需要简单考虑一下,如果打印结果的要求是“逐层”?

比如上述二叉树,打印结果为:
8
6 10
5 7 9 11

 

    此时我们发现一个队列其实无法满足设计需要,我们需要用两个队列:

1)
队列1     队列二
8            空
空           6 10

2)
队列1      队列二
空           6 10
5 7          10
5 7 9 11   空

基本思路就是,在将其中一个队列出队的时候,将其
子节点添加到另一个队列的尾部,且每次都将当前队列
完全出队,此后再以同样的方式操作另一个队列。

 

    代码样例:

public static void print(BinaryTree tree) {
    if(tree == null) {
        return;
    }
    BinaryTreeNode root = tree.root;
    if(root == null) {
        return;
    }
    Queue<BinaryTreeNode> first = new LinkedList<>();
    Queue<BinaryTreeNode> second = new LinkedList<>();
    first.add(root);
    while (true) {
        if(first.isEmpty() && second.isEmpty()) {
            break;
        }
        if(first.isEmpty()) {
            inner(first,second);
        }else {
            inner(second,first);
        }
    }

}
private static void inner(Queue<BinaryTreeNode> first,Queue<BinaryTreeNode> second) {
    while (!second.isEmpty()) {
        BinaryTreeNode current = second.poll();
        System.out.print(current.value + ",");
        BinaryTreeNode left = current.left;
        if(left != null) {
            first.add(left);
        }
        BinaryTreeNode right = current.right;
        if(right != null) {
            first.add(right);
        }
    }
    System.out.println();
}

 

四、输入一个整数数组,判断该数组是否为某二叉搜索树的后序遍历结果

    我们首先分析一下二叉树后序遍历结果的特点,比如{5,7,6,9,11,10,8}是一个正常的二叉树后序遍历结果;最后一个元素一定是root节点,即为8;从数组的一个元素开始,首次遇到的比8大的元素之前的元素列表都是8的左子树,其他的为右子树,比如{5,7,6}为左子树,{9,11,10}为右子树。当然每个子树也是“后序遍历”的结果,比如对于左子树,6就是其根节点,5是其左节点,7是有节点。这种比较的合法性是可传递的,即任何节点的左子树元素都应该小于它的值,右子树的元素都大于它的值。(无重复元素)

 

    比如输入{7,4,6,5},判断这个序列是否为后序遍历结果;由此得知:5是跟节点,{7,4,6}是它的右子树,但是其中4小于5,不符合判定规则,因此判断结果为false。

 

    代码样例:

public static boolean check(int[] source,int start,int end) {
    if(start == end) {
        return true;
    }
    int root = source[end];
    int i = start;
    //判断左子树的位置
    for(;i < end; i++) {
        if(source[i] > root) {
            break;
        }
    }
    int j = i;
    for(;j < end - 1;j++) {
        if(source[j] < root ) {
            return false;
        }
    }
    boolean left = true;
    if(i > 0) {
        left = check(source, start, i - 1);
    }

    if(!left) {
       return false;
    }
    boolean right = true;
    if (i < end - 1) {
        right = check(source, i, end - 1);
    }
    return left && right;
}

 

分享到:
评论

相关推荐

    JAVA算法编程题目及答案.doc

    JAVA算法编程题目及答案 本资源提供了50道JAVA算法编程题目及答案,涵盖了算法设计、数据结构、程序设计等多个方面的知识点。以下是对标题、描述、标签和部分内容的详细解释: 标题:JAVA算法编程题目及答案 本...

    C#数值计算算法编程(周长发)

    C#数值计算算法编程 周长发,有利于数值算法编程开发

    并行计算——结构·算法·编程习题答案

    本资料主要关注并行计算的三个方面:结构、算法和编程,旨在通过习题解答帮助学习者深入理解和应用这些概念。 1. **并行计算结构**: 并行计算结构通常分为共享内存和分布式内存两大类。共享内存系统中,所有...

    算法&&编程

    《算法&&编程》这个主题包含了两个至关重要的计算机科学领域,它们是解决问题和构建软件系统的基础。算法是设计解决特定问题的步骤序列,而编程则是将这些算法转化为计算机可执行的语言。这里,我们深入探讨这两个...

    java 遗传算法 编程

    通过阅读本书,你将熟悉遗传算法与编程语言相关的问题和概念,掌握构建自己的算法所需的全部知识,并且将获得用遗传算法解决问题的能力。请拿起本书,进入遗传算法这个迷人的领域,看看真正能工作的Java代码,并运用...

    C#数值计算算法编程.zip

    12 用 C#实现数伯叶算算法的要点 7 第 2 章 复数运算 .................................. · ·12 2.1 复数类设计 12 2.2 复数乘法 25 23 复数附法 26 2.4 复数的膜 书,27 25 复数的根 28 2.6 复数的实茄指数 29...

    [并行计算——结构·算法·编程].陈国良.文字版

    并行计算 陈国良编著 呵呵 大家来下载 是第三版《并行计算:结构•算法•编程(第3版)》是并行计算系列丛书之开篇,它以并行计算为主题,围绕并行计算机、并行算法和并行程序设计展开讨论,强调融并行计算机体系结构、...

    并行计算——结构·算法·编程 习题答案

    在《并行计算——结构·算法·编程》这本书中,作者深入探讨了这一主题,提供了丰富的习题来帮助读者理解和掌握相关概念。现在,我们来详细探讨这些习题答案中可能涵盖的知识点。 首先,结构方面,可能包括以下内容...

    游戏核心算法编程内幕.pdf

    游戏算法电子书 感觉不错 分享给大家 游戏核心算法编程内幕.pdf

    游戏核心算法编程内幕

    《游戏核心算法编程内幕》由三部分组成。其中第一部分主要介绍游戏编程的基本概念;第二部分详细介绍游戏编程中的各种技术和算法;第三部分是附录,介绍游戏编程中相关技术和知识以及其他相关读物。《游戏核心算法...

    JAVA遗传算法编程pdf版本书籍

    《JAVA遗传算法编程》这本书是面向对遗传算法有兴趣并希望通过Java语言进行实现的读者的一本专业指南。遗传算法(Genetic Algorithm,简称GA)是一种基于生物进化论中的自然选择和遗传原理的优化方法,它在解决复杂...

    C#数值计算算法编程

    PDF格式的C#数值计算算法编程,记录了各种初级、高级算法。

    java遗传算法编程pdf

    一本基于java遗传算法编程技术的讲解书书籍,全书讲解很全面,适合对遗传算法感兴趣的读者。本书共分为6章,每章都会有实例。

    编程珠矶算法

    第三本书可能涉及动态规划、回溯法、贪心策略和分支限界等高级算法。动态规划用于解决具有重叠子问题和最优子结构的问题,如背包问题和斐波那契数列。回溯法用于在庞大的解决方案空间中寻找解,如八皇后问题和迷宫...

    Python编程入门与算法进阶.pptx

    "Python编程入门与算法进阶.pptx" Python编程入门与算法进阶是一本全面介绍Python编程语言和算法的书籍。本书分为两个部分,第一部分是Python编程入门,第二部分是算法进阶。 在Python编程入门部分,本书详细讲解...

    Scratch编程入门与算法进阶.pptx

    《Scratch编程入门与算法进阶》是一本面向青少年和初学者的Scratch编程和算法教育书籍,本书以图文并茂的方式,系统地介绍了Scratch编程的基础知识和常用算法,旨在帮助读者深入理解计算机编程的基本概念和思想,...

    编程语言算法100例

    在编程领域,算法是解决问题的核心工具,它们是逻辑和数学思维在编程中的应用。"编程语言算法100例"这个资源集成了多种编程语言下的基础算法实例,旨在帮助程序员理解和掌握算法的基本概念,以及如何在实际编程中...

Global site tag (gtag.js) - Google Analytics