zoukankan      html  css  js  c++  java
  • 一些数据结构的思想(2)

    • 1000瓶水中找 出有毒的那瓶,毒性一周后发作,一周内最少需要多少只老鼠

      这个题是对bit位的应用,1000接近1024,所以需要10个bit位,对瓶子进行编号,从0到999,这样需要10只老鼠。瓶子的编号分别为:

      00000,00000

      00000,00001

      00000,00010

      00000,00011

      00000,00101

      00000,00111

      。。。。。。

      11111,00111

      同时给老鼠编号,从1,2,...10,从低位开始,让第n个老鼠喝下第n个bit位为1瓶子中的药水。一周后,若所有的老鼠都没有发病,那么是第一个瓶子有毒,如果有一些老鼠发病,那么从低到高的bit位置成1,其他的还是0。变成整数后,对应的数字即为有毒药水的编号。

    • 给定一个单词a,如果通过交换单词中字母的顺序可以得到另外的单词b,那么定义b是a的兄弟单词,例如单词army和mary互为兄弟单词。现在给定一个字典,用户输入一个单词,如何根据字典找出这个单词有哪些兄弟单词?要求时间和空间效率尽可能的高

      解法一:

      使用hash_map和链表。

      首先定义一个key,使得兄弟单词有相同的key,不是兄弟的单词有不同的key。例如,将单词按字母从小到大重新排序后作为其key,比如bad的key为abd,good的key为dgoo。

      使用链表将所有兄弟单词串在一起,hash_map的key为单词的key,value为链表的起始地址。
      开始时,先遍历字典,将每个单词都按照key加入到对应的链表当中。当需要找兄弟单词时,只需求取这个单词的key,然后到hash_map中找到对应的链表即可。

      这样创建hash_map时时间复杂度为O(n),查找兄弟单词时时间复杂度是O(1)。

      解法二:

      同样使用hash_map和链表。

      将每一个字母对应一个质数,然后让对应的质数相乘,将得到的值进行hash,这样兄弟单词的值就是一样的了,并且不同单词的质数相乘积肯定不同。

      使用链表将所有兄弟单词串在一起,hash_map的key为单词的质数相乘积,value为链表的起始地址。

      对于用户输入的单词进行计算,然后查找hash,将链表遍历输出就得到所有兄弟单词。

      这样创建hash_map时时间复杂度为O(n),查找兄弟单词时时间复杂度是O(1)。

    • 判断两个数组中是否有相同的数字

      首先要说声不好意思,因为这个题说的很模糊,但是也算是两个方向吧。也就是说,给定的两个数组是否有序,如果无序的话那么解决这个问题所用的时间复杂度就是nlog(n),如果给定的两个数组有序,那么解决方法的时间复杂度会是O(n)。下面会给出两个解法。(假设数组是有序的,因为如果无序的话直接用快速排序或者堆排序在nlog(n)就可以解决)。

      第一种方法,就是应用折半查找,依次从第一个数组中取出一个元素,到第二个数组中应用折半查找方法去寻找。这样一个循环内层加折半查找的嵌套,总得时间复杂度应该是mlog(n)(m,和n分别是两个数组的长度)。

      第二种方法就是设定两个指针,分别指向第一个数组和第二个数组。取出指向的元素进行比较,如果ai<bj(因为数组是有序的),所以说明如果存在ak=bj,那么k应该在i之后,所以i得加1,如果i加1了以后,bj < a(i+1),那么说明和a(i+1)相等的b数组中的元素要在bj之后,所以j要加1。依次类推,直到找到ai=bj,或者不存在,循环结束为止。这个算法的时间复杂度是Om+n).(m和n分别指两个数组的长度)。

    • 同时寻找一个数组中的最大元素和最小元素

      给定一个数组a,含有n,寻找这个数组中的最大元素和最小元素,刚看到这个题目的时候,觉得这个问题没什么思考性,因为这个问题很简单,就是设定一个初始最大值和初始最小值,然后循环遍历数组,进行比较,至多会在2(n-1)的时间内找到最大值和最小值。下面给出一种分析的方法,使得这个问题能够在3*(n/2)内结束。首先要判定n是奇数还是偶数,

      如果是奇数的话,假设min=max=a[1].然后遍历数组,但是这时候每次取两个数字,并把这两个数字进行比较,将较大的值和max进行比较,较小的值和min进行比较。这样循环 会在(n-1)/2或者(n-2)/2次后结束,这样比较的次数就变为每次循环要比较三次。这个方法对于n值很小的数组来说,没什么太大的影响,但是如果数组的n值很大的话,那时间减少了相当于原来的四分之一。

    • 长度为1的线段,随机在其上选择两点,将线段分为三段,问这3个字段能组成一 个三角形的概率是多少
    • 把x,y的取值放在坐标轴上进行考虑,从0到1的那段。那三条边的长度就为x,y-x,1-y。

      假设我们选择的两个点的坐标是x和y(先假设x < y):

      那么由三角形两边和大于第三边的性质,有:

      x+y-x>1-y

      x+1-y>y-x

      1-y+y-x>x

      由上述不等式得到:x < 0.5, 0.5 < y < x+0.5 

      然后画个图就能得到联合概率为1/8,不要忘了这个结果是在假设x < y时得来的,所以再乘以2,得到1/4。

    • 单链表的反转
    • (1)设置三个变量,p,q,t,分别指向三个节点,然后遍历一遍单链表,改变各个节点的指针的指向,但是这个方法会很绕,如果没有清晰的思路很容易把自己绕晕。

      (2)使用栈。可以一次遍历链表,把链表中的各个节点存入到堆栈中,然后在操作栈,因为栈的特性是后进先出,那么这样很简单的就可以把链表反转。

      (3)重新设置一个头节点,让其代表一个新的链表,然后依次遍历之前给定的链表,每次遍历取出一个节点,插入到新链表的开头,那么这样一次遍历之后就重新建立了一个链表,而且是之前链表的反转,

    • 位操作交换两数
    • void Swap(int &a, int &b)
       {
           if (a != b)
           {
               a ^= b;
               b ^= a;
              a ^= b;
           }
       }
    • 二进制中1的个数
    • 统计二进制中1的个数可以直接移位再判断,当然像《编程之美》书中用循环移位计数或先打一个表再计算都可以。本文详细讲解一种高效的方法。以34520为例,可以通过下面四步来计算其二进制中1的个数。

      第一步:每2位为一组,组内高低位相加

            10 00 01 10  11 01 10 00

        -->01 00 01 01  10 01 01 00

      第二步:每4位为一组,组内高低位相加

            0100 0101 1001 0100

        -->0001 0010 0011 0001

      第三步:每8位为一组,组内高低位相加

            00010010 00110001

        -->00000011 00000100

      第四步:每16位为一组,组内高低位相加

            00000011 00000100

        -->00000000 00000111

      这样最后得到的00000000 00000111即7即34520二进制中1的个数。类似上文中对二进制逆序的做法不难实现第一步的代码:

      x = ((x & 0xAAAA) >> 1) + (x & 0x5555);

    • 如何将一棵树转换成二叉树?
    • 解答:

      1. 将 节点的孩子 放在左子树;

      2. 将 节点的兄弟 放在右子树。

      延伸:

      任何一棵树都可以表示成二叉树,并不是任何一棵二叉树都可以表示成树。那么树多还是二叉树多?

      1. 任何一棵树都可以表示成二叉树,结合以上题目很容易理解。

      2.不是任何一棵二叉树都可以表示成树:

      当根节点包含右子树的时候,就无法表示成树了。

      3. 树多还是二叉树多的问题:

      二叉树也是树的一种,如果按照包含关系来说,树肯定包含二叉树了,树多一些

      • 从19本书中选取五本,并且要求这五本互相不相邻,一共有多少种方法?

      题目:

      从19本书中选取五本,并且要求这五本互相不相邻,一共有多少种方法?

      解决方案一:挡板问题——插空法

      假设当前在书架上已经放好14本书,那么只需要再把剩下五本书插入这些空中即可。

      14本书有15个可以插入的空,因此,总共方法有:C(15,5)。

      解决放啊二:二进制

      转化成二进制方式,0表示选中国,1表示未选中。则题意转变成,要求00不能相邻。

      可以编程遍历来实现。

      • 求一个有序整数数组中和为K的数的对数

      题目:

      求一个有序整数数组中和为K的数的对数。

      解决方案:

      两个指针,一个在头,一个在尾;

      大则-,小则加。

      延伸题目:

      (1)求整数数组中和为K的对数。

      先排序,O(N*logN),在按照以上算法查找O(N)。

      (2)求一个整数数组差为K的数的对数。

      先排序,O(N*logN),然后,用两个指针均从头部开始,一个先走一个后走,差过小则前指针++,差过大则后指针++。

      这里需要考虑一个问题,如果数组中有重复元素的话,需要做处理。

      我是天王盖地虎的分割线                                                                 

      参考:http://blog.csdn.net/yahohi

  • 相关阅读:
    Spring中使用存储过程
    使用mysql-connector-java.jar连接MySql时出现:Error while retrieving metadata for procedure columns: java.sql.SQLException: Parameter/Column name pattern can not be NULL or empty.
    Spring的JDBC示例
    使用JDBC连接MySql时出现:The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration
    Spring的JDBC框架概述
    数据库中的DDL/DML/DCL解释(转)
    沉默的螺旋--digest
    左边老师长征--性命、生命、使命
    柬埔寨旅游小结
    Spring Security 源码分析(四):Spring Social实现微信社交登录
  • 原文地址:https://www.cnblogs.com/yydcdut/p/3876637.html
Copyright © 2011-2022 走看看