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

算法编程(一)

 
阅读更多

一、字符串转换成数字

    设计要求:将输入的任意字符串,转换成数字(int类型),如果转换失败则抛出异常。

    输入:"1234","+1234","-1234","1234567890","1234ab"

    输出:1234,1234,-1234,异常,异常

 

    思路:字符串有字符序列组成,每个字符都对应ASCII值,比如字符'0'为48,‘1’为49...'9'为57,你或许不知道它们对应的具体值,但是需要知道字符‘0’~‘9’的ASCII值是连续的即可。任何数组字符与‘0’字符的ASCII值的差值即可以表示其实际数字,比如:'5' - '0' = 5。代码样例如下:

    需要注意:

    1)不合法字符,不能参与计算

    2)兼顾字符串开头的“+”、“-”字符

    3)因为int数字,有最大值、最小值边界,所以计算时如果越界应该抛出异常

 

public static int parseToInteger(String value) {
    if(value == null || value.isEmpty()) {
        throw new RuntimeException("null!");
    }
    //合法前缀“-”,“+”
    int start = 0;
    char[] chars = value.toCharArray();
    char first = chars[0];
    if(first == '-' || first == '+') {
        start = 1;
    }
    boolean negative = false;
    if (first == '-') {
        negative = true;
    }

    //合法数字字符的边界
    int zero = '0';
    int nigh = '9';
    int result = 0;
    for(int i= start; i < chars.length; i++) {
        char item = chars[i];
        if(item < zero || item > nigh) {
            throw new RuntimeException("Format error!");
        }
        int current = (item - '0');
        //检测边界,int的最大值与最小值
        if(negative) {
            if(Integer.MIN_VALUE + result * 10 + current > 0) {
                throw new RuntimeException("too small!");
            }
        } else {
            if (Integer.MAX_VALUE - result * 10 < current) {
                throw new RuntimeException("too big!");
            }
        }
        result = result * 10 + current;
    }

    return negative ? 0 - result : result;

}

 

二、从二维数组中判断“目标数字”是否存在

    有一个二维数组,元素值为整型数字;二维数组的数据特征为:每行、每列元素均是按照从小到大排列,数字可能重复。问题:指定一个目标数字,请判断二维数组中是否存在此值,如果存在则返回true,否则返回false。

 

    数据模型样例解释:

1 2 8 9
2 4 9 12
4 7 10 13
6 9 11 15

 

    比如上述二维数组,每行、每列都是有序的,假如目标数字为“7”,则判定结果应该为true;如果目标数字为“20”,那么判定结果应该为false。

    思路:这个题如果作为面试题,还是稍微有些复杂,涉及到查找路径问题。二维数组的每个元素都有特征:左边与上边的元素比它小,右边和下边的元素比它大。如果“目标数字”比当前元素小,那么查找方向应该往其左边或者上边,否则就是往其右边或者下面。我们暂定,查找路径优先“左右”,然后再“上下”(具体由你选定的起始点决定)。

假如在如下数组中查找“7”是否存在,我们将二维数组的“右上角”作为起始点(起始点的选择,可以随意,只是这样编程稍微简单):
1 2 8 9
2 4 9 12
4 7 10 13
6 9 11 15

查找路径如下:
1 2 <- 8 <- 9
  \/
2 4      9      12  
  \/
4 7      10    13
6 9      11    15

 

   代码示例:

public static boolean find(int[][] arrays,int row,int column,int target) {
    try {
        int item = arrays[row][column];
        //System.out.println(item);//打印路径
        if (item == target) {
            return true;
        } else if (arrays[row][column] > target) {
            return find(arrays, row, column - 1, target);
        } else {
            return find(arrays, row + 1, column, target);
        }
    } catch (Exception e) {
        //
    }
    return false;
}

 

三、书写一段程序,将数组转换成单向链表,并反向输出此链表的数值

    考察2个点,第一:构建一个单向链表,第二:反向输出链表的数值。构建一个单向链表本身并不难,但易于出错,主要考察编程人员对数据结构的认识;难点就在于“如何反向输出单向链表的节点值”;单向链表只能向下驱动(next),所以我们即使找到了单向链表的尾部,仍然不能反向输出,因为无法“向上”查找。解题的关键可以根据实际情况而定,如果允许额外的使用其他数据结构,那么我们可以在遍历单向链表时将节点逐个加入到“栈”中(Stack,先进后出),然后使用stack的特性逐个输出即可(pop);如果不允许使用额外的数据结构,那么我们可以考虑使用“递归”的方式(原理也类似于栈)遍历。

 

    输入:1,2,3,4,5,6

    输出:6,5,4,3,2,1

    代码样例:

public static void main(String[] args) {
    int[] source = {1,2,3,4,5,6,7};
    LinkedNodes linkedNodes = buildLinked(source);
    print(linkedNodes);
}

static class LinkedNodes {
    Node header = new Node();//header仅仅为标记性节点
    Node tail;
}
static class Node {
    Node next;
    int value;
}

public static LinkedNodes buildLinked(int[] source) {
    LinkedNodes linked = new LinkedNodes();
    for(int i = 0; i < source.length; i++) {
        Node node = new Node();
        node.value = source[i];
        if(i == 0) {
            linked.header.next = node;
            linked.tail = node;
        }else {
            linked.tail.next = node;
            linked.tail = node;
        }
    }

    return linked;

}

private static void print(LinkedNodes linkedNodes) {
    if(linkedNodes == null || linkedNodes.header.next == null) {
        return;
    }
    print(linkedNodes.header.next);
}

private static void print(Node node) {
    if(node == null) {
        return;
    }
    Node current = node.next;
    if(current != null) {
        print(current);
    }
    System.out.print(node.value + ",");
}

 

四、请将指定数组构建成一个二叉树,并使用“前序”遍历打印此树(或者:中序遍历、后序遍历)

    首先需要知道如何构建一个二叉树,二叉树的特征:每个节点最多有两个子节点,分别为左右节点,对于任何一个节点,其左节点都比自己小,右节点都比自己大。

    前序、中序、后序遍历的区别,主要是“中间”节点的位置(相对于左、右节点),比如前序遍历,表示中间节点在前面(中-->左-->右),中序遍历表示当前节点在“中间”(左-->中-->右)。

 

    第一:构建二叉树,主要考察编程技能和对数据结构的认识,第二:遍历的方式,如果了解了上面的原理,遍历的编程应该水到渠成。

 

    输入:一个数组,这个数组表示一个由宽度遍历后的满二叉树(特别注意,如果不是完全二叉树,实现方式完全不同)。

    输出:前序遍历

比如输入数组:[10,6,14,4,8,12,16]

构建的二叉树应该为:
   10
   |
 6    14
 |     |
4 8  12 16

 

    第一步,先将数组构建成一个二叉树(平衡二叉树,完全二叉树),非常棘手,既然是一个“平衡、完全二叉树”,我们可以从树的节点与数组的索引位置对应关系找突破口:

树节点与数组索引对应关系:

当前节点      左节点  右节点
10(0)       6(1)   14(2)
6(1)         4(3)    8 (4)
14(2)       12(5)  16(6)

如果当前节点对应数组的索引位置为N,可以得出:
左节点:2 * N + 1
右节点:2 * (N + 1)

 

    代码样例如下:

public static void main(String[] args) throws Exception{
    int[] source = {10,6,14,4,8,12,16};

    BinaryTree tree = new BinaryTree();
    BinaryTreeNode root = new BinaryTreeNode();
    tree.root = root;
    root.value = source[0];
    buildTree(root, source, 0);
}

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

private static void buildTree(BinaryTreeNode current,int[] source,int currentIndex) {
    int leftIndex = currentIndex * 2 + 1;
    int rightIndex = (currentIndex + 1) * 2;
    int max = source.length;//可以不用每次都计算
    if(leftIndex < max) {
        BinaryTreeNode leftNode = new BinaryTreeNode();
        leftNode.value = source[leftIndex];
        current.left = leftNode;
        buildTree(leftNode, source, leftIndex);
    }

    if(rightIndex < max) {
        BinaryTreeNode rightNode = new BinaryTreeNode();
        rightNode.value = source[rightIndex];
        current.right = rightNode;
        buildTree(rightNode, source, rightIndex);
    }
}

 

    1)前序遍历代码样例:

public static void main(String[] args) throws Exception{
	//....
    front(tree.root);
}

private static void iterate(BinaryTreeNode current) {
    BinaryTreeNode left = current.left;
    System.out.print(current.value + ",");
    if(left != null) {
        iterate(left);
    }
    BinaryTreeNode right = current.right;
    if(right != null) {
        iterate(right);
    }
}

 

    2)中序遍历代码样例:

private static void iterate(BinaryTreeNode current) {
    BinaryTreeNode left = current.left;
    if(left != null) {
        iterate(left);
    }
    System.out.print(current.value + ",");
    BinaryTreeNode right = current.right;
    if(right != null) {
        iterate(right);
    }
}

 

    与前序遍历的唯一差别,就是打印当前节点的时机,即先遍历完左节点之后才打印。那么“后序遍历”同理!

 

五、指定二叉树的“前序遍历”数组、“中序遍历”数组,请根据上述2个数组来重建此二叉树。

    从上题中我们已经知道,二叉树的三种遍历方式,这个题正好相反,我知道了二叉树的遍历的结果,我们要反向重建二叉树。(备注:前序 + 中序、中序 + 后续可以重建二叉树,只知道其中一种,是无法完全重建原有的二叉树)

    输入:二叉树的前序、中序遍历结果,比如前序、中序遍历结果分别为[1,2,4,7,3,5,6,8]、[4,7,2,1,5,3,8,6]。

    输出:无输出,构建一个二叉树。(备注:可以输出为此二叉树的“后序遍历”结果)

 

    这道题已经算是比较复杂了,通常现场面试、笔试的话已不太适合,比较耗时。主要考察对二叉树遍历的原理,以及反向思维。

前序:
1  2  4  7  3  5  6  8
中序:
4  7  2  1  5  3  8  6
构建结果:
        1
        |
   2        3
    /        |
   4     5     6
   \             /
    7          8


前序的特点就是“中”--“左”--“右”,对于任何二叉树包括其子二叉树,root节点总是位于第一个,比如本例中“1”就是此二叉树的root节点。

中序的特点就是“左”--“中”--“右”,对于二叉树包括其子二叉树,遍历结果中root节点值的左边一定是左子树,右边一定是右子树。

最终规律是:根据前序结果找到二叉树(递归是为二叉树子树)的root节点,根据中序结果找到“左子树”、“右子树”。

根据前序结果我们得出顶层的root节点是1,然后在中序结果中找到1的位置,1的两侧分别为root的“左子树”、“右子树”。

第一次拆分:
1  [2  4  7]  [3  5  6  8]
[4  7  2]  1  [5  3  8  6]
通常是根据”中序“找到左右子树后,分别计算左右子树的元素个数,比如本次拆分,左子树为3个元素,右子树为4个元素;然后在”前序“结果中,紧邻root的3个元素也是”左子树“,此后的四个元素是”右子树“。

然后递归:分别让它们的左子树和右子树,也按照上述原理,查找root,然后继续拆分子树....
左子树的前序:2 4 7
左子树的中序:4 7 2
此左子树的root节点为2,然后继续拆分...

右子树的前序:3 5 6 8
右子树的中序:5 3 8 6
此右子树的root节点为3,然后继续拆分...

 

    代码样例如下:

public static void main(String[] args) throws Exception{
    int[] preOrder = {1,2,4,7,3,5,6,8};//前序
    int[] inOrder = {4,7,2,1,5,3,8,6};//中序

    BinaryTree tree = new BinaryTree();
    BinaryTreeNode root = new BinaryTreeNode();
    tree.root = root;
    buildTree(root,preOrder,0,preOrder.length - 1,inOrder,0,inOrder.length - 1);
    iterate(root);
    System.out.println("");
    iterate1(root);
}

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

private static void buildTree(BinaryTreeNode current,int[] preOrder,int preStart, int preEnd,int[] inOrder,int inStart,int inEnd) {

    int value = preOrder[preStart];
    current.value = value;
    if(preStart == preOrder.length -1 || inStart == inOrder.length - 1) {
        return;
    }
    int nextRoot = -1;

    for(int i = inStart; i <= inEnd; i ++ ) {
        if(inOrder[i] == value) {
            nextRoot = i;
            break;
        }
    }
    if (nextRoot == -1) {
        throw new RuntimeException("Error!");
    }

    int leftLength = nextRoot - inStart;
    if(leftLength > 0) {
        BinaryTreeNode left = new BinaryTreeNode();
        current.left = left;
        buildTree(left, preOrder, preStart + 1, preStart + leftLength, inOrder, inStart, nextRoot - 1);
    }

    int rightLength = inEnd  - nextRoot;
    if(rightLength > 0) {
        BinaryTreeNode right = new BinaryTreeNode();
        current.right = right;
        buildTree(right, preOrder, preEnd + 1 - rightLength, preEnd, inOrder, nextRoot + 1, inEnd);
    }

}

 

分享到:
评论

相关推荐

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

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

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

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

    算法&&编程

    例如,在设计一个搜索引擎时,我们需要使用倒排索引(一种特殊的数据结构)和搜索算法来快速响应用户的查询;在开发社交网络平台时,可能需要运用图论算法来分析用户之间的关系,或者使用动态规划来推荐最合适的匹配...

    算法编程大赛题目(.zip)

    在本资源中,"算法编程大赛题目(.zip)"包含了一系列来自谷歌算法大赛的编程挑战,这些挑战旨在提升编程思维并锻炼解决复杂问题的能力。以下是这些算法问题的详细解析和相关知识点: 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...

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

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

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

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

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

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

    游戏核心算法编程内幕

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

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

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

    java遗传算法编程pdf

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

    C#数值计算算法编程

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

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

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

    基于VC++的遗传算法编程实现

    在这个基于VC++的遗传算法编程实现中,我们将深入探讨如何在Visual C++环境中构建一个有效的遗传算法程序。 首先,理解遗传算法的基本步骤至关重要。这些步骤包括初始化种群、选择、交叉和变异: 1. **初始化种群*...

    编程语言算法100例

    总的来说,"编程语言算法100例"是一个宝贵的教育资源,无论你是正在学习编程的新手,还是希望巩固和扩展算法知识的资深开发者,都能从中受益。通过深入研究这些实例,你可以更好地理解和运用算法,从而在编程世界中...

    编程珠矶算法

    第一本书可能涵盖基础算法,如排序和搜索。排序算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序等,它们都是处理数据集合的关键工具。搜索算法则涉及线性搜索、二分搜索和哈希表查找,帮助我们在大量数据...

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

    Python编程入门与算法进阶是一本全面介绍Python编程语言和算法的书籍。本书分为两个部分,第一部分是Python编程入门,第二部分是算法进阶。 在Python编程入门部分,本书详细讲解了Python编程的基础知识,包括变量、...

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

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

Global site tag (gtag.js) - Google Analytics