zoukankan      html  css  js  c++  java
  • 记一道有趣的Twitter面试题

      微信上的“程序员的那些事”想必是很多码农们关注的公众账号之一,我也是其粉丝,每天都会看看里面有没有什么趣事,前段时间“程序员的那些事”分享了一篇博文《我的Twitter技术面试失败了》挺有意思,链接如下http://mp.weixin.qq.com/mp/appmsg/show?__biz=MjM5OTA1MDUyMA==&appmsgid=10000710&itemidx=1&sign=fab77147279ef685c50e39cc06623e5d&uin=MjM3Mjc1NTIwMA%3D%3D&key=38b17fed399880fb7129f69083fd038240b4873f89a22a1bf82803ef35479ff9dda602589570716d1a73ae7c3e9f739d&devicetype=android-17&version=25000105&lang=zh_CN

      里面说到了一道算法题,给出一个数组,将其转化为二维坐标系的点,并且连接每个点形成一个“容器”状的图形,问“容器”能装多少水(详情参照上面的链接)。这道题吸引我的原因是,每当说到算法题,许多公司总是喜欢考一些查找、排序、大数据处理等等,没什么多新意,也考不了程序员的思维能力(面试前复习下《数据结构》即可);而这道题很有新意,引发了我做一做的欲望,顺便也开拓一下思维,毕竟在实际工作中还是很少用到算法的。

      第一次解题:思路很自然地想到从左到右遍历数组,确定左右底部的位置(即一个“蓄水区域”),进行一次容积的计算,然后将指针移动到此“蓄水区域”的右侧,继续确定下一个“蓄水区域” 的左右底部位置,再进行一次容积的计算...直到数组最右端,代码如下:

      1 /*
      2  * waterHolder.c
      3  *
      4  *  Created on: 2013-11-5
      5  *      Author: pengyiming
      6  *      Description: 1,输入如下的非负数组(2, 5, 1, 2, 4),将其转化到二维坐标系中的点((2, 0), (2, 1), (5, 1), (5, 2), (1, 2), (1, 3), (2, 3), (2, 4), (4, 4), (4, 5))
      7  *                   2,连接上述个点形成一个"容器"
      8  *                   试问"容器"可装多少水,以1x1方格为单位
      9  *      Answer: 第一次遍历,从左向右遍历数组,找出左右侧最高点
     10  *              第二次遍历,遍历左右侧最高点之间的数组,计算容积
     11  */
     12 
     13 #include <stdio.h>
     14 
     15 /* 宏begin */
     16 #define TRUE 1
     17 #define FALSE 0
     18 /* 宏end */
     19 
     20 /* 输入数据begin */
     21 static const unsigned int WATER_BUCKET[] = { 6, 1, 4, 6, 7, 5, 1, 6, 4 };
     22 /* 输入数据end */
     23 
     24 int main(int argc, char *argv[])
     25 {
     26     int volume = 0;
     27 
     28     // "容器"左右侧高度,底部高度
     29     int leftHeight = 0;
     30     int bottomHeight = 0;
     31     int rightHeight = 0;
     32 
     33     // "容器"左右侧高度,底部高度位置
     34     int leftPos = 0;
     35     int bottomPos = 0;
     36     int rightPos = 0;
     37 
     38     // "容器"左侧高度,底部高度确定状态
     39     int leftPosOK = FALSE;
     40     int bottomPosOK = FALSE;
     41 
     42     // 遍历数组以获取"容器"中的每个蓄水区域
     43     int length = sizeof(WATER_BUCKET) / sizeof(unsigned int);
     44     while (TRUE)
     45     {
     46         int i;
     47         for (i = rightPos; i < length; i++)
     48         {
     49             // 寻找左侧位置
     50             if (!leftPosOK && WATER_BUCKET[i] >= leftHeight)
     51             {
     52                 leftHeight = WATER_BUCKET[i];
     53                 leftPos = i;
     54 
     55                 bottomHeight = WATER_BUCKET[i];
     56             }
     57 
     58             // 寻找底部位置,确定左侧位置
     59             if (!bottomPosOK && (WATER_BUCKET[i] < bottomHeight))
     60             {
     61                 bottomHeight = WATER_BUCKET[i];
     62                 bottomPos = i;
     63 
     64                 leftPosOK = TRUE;
     65                 rightHeight = WATER_BUCKET[i];
     66             }
     67 
     68             // 寻找右侧位置,确定底部位置
     69             if (leftPosOK && (WATER_BUCKET[i] > rightHeight))
     70             {
     71                 rightHeight = WATER_BUCKET[i];
     72                 rightPos = i;
     73 
     74                 bottomPosOK = TRUE;
     75 
     76                 // 优化:若右侧高度已经大于等于左侧高度,则已确定右侧位置,无需遍历完数组
     77                 if (rightHeight >= leftHeight)
     78                 {
     79                     break;
     80                 }
     81             }
     82 
     83             printf("loop : left = %d, right = %d, bottom = %d
    ", leftPos, rightPos, bottomPos);
     84         }
     85 
     86         if (bottomPos > leftPos
     87                 && rightPos > bottomPos)
     88         {
     89             volume += countVolume(leftPos, rightPos, bottomPos);
     90 
     91             // 重置并计算下一个"蓄水区域"
     92             leftHeight = 0;
     93             bottomHeight = 0;
     94             rightHeight = 0;
     95 
     96             leftPos = rightPos;
     97             bottomPos = rightPos;
     98 
     99             leftPosOK = FALSE;
    100             bottomPosOK = FALSE;
    101         }
    102         else
    103         {
    104             // 可能在"容器"中有多个蓄水区域,遍历可能需要多次,设定一个变量标识是否找到蓄水区域,当找不到时退出
    105             break;
    106         }
    107     }
    108 
    109     printf("total volume = %d
    ", volume);
    110 
    111     return 0;
    112 }
    113 
    114 int countVolume(int leftPos, int rightPos, int bottomPos)
    115 {
    116     printf("count volume : left = %d, right = %d, bottom = %d
    ", leftPos, rightPos, bottomPos);
    117 
    118     if (WATER_BUCKET[leftPos] == WATER_BUCKET[bottomPos]
    119           || WATER_BUCKET[rightPos] == WATER_BUCKET[bottomPos])
    120     {
    121         return 0;
    122     }
    123 
    124     // "容器"能装多少水取决于最短一侧的高度
    125     int minHeight = WATER_BUCKET[leftPos];
    126     if (minHeight > WATER_BUCKET[rightPos])
    127     {
    128         minHeight = WATER_BUCKET[rightPos];
    129     }
    130 
    131     int volume = 0;
    132     int i;
    133     for (i = leftPos + 1; i < rightPos; i++)
    134     {
    135         volume += minHeight - WATER_BUCKET[i];
    136     }
    137 
    138     return volume;
    139 }

      上述算法通过了链接中及我自己列举的测试用例,说明上述代码确实能工作,但是其中掺杂了太多奇怪的boolean变量来帮助确定左右底部的位置,这使得代码可读性不好,且逻辑不够清晰,最近发完版后又闲下来了,重新理解了一下链接中的解题思路,确实比这段算法的思路清晰很多。

      第二次解题:第一次遍历确定“容器”最高点,从而将“容器”一分为二,接下来只要分别确定“容器”左右侧最高点,并计算左右侧容积即可(“容器”左右侧最高点必定小于“容器”最高点,根据“木桶原理”,用左右侧最高点计算容积)。

      多插一句,给出的数组是线性的,但是不见得非要从左到右遍历去解决问题,可以试一试上面这种分治的思路,线性的数组一分为二,分别通过左右两侧的子遍历来解决问题,代码如下:

     1 /*
     2  * waterHolder2.c
     3  *
     4  *  Created on: 2013-11-19
     5  *      Author: pengyiming
     6  *      Description: 1,输入如下的非负数组(2, 5, 1, 2, 4),将其转化到二维坐标系中的点((2, 0), (2, 1), (5, 1), (5, 2), (1, 2), (1, 3), (2, 3), (2, 4), (4, 4), (4, 5))
     7  *                   2,连接上述个点形成一个"容器"
     8  *                   试问"容器"可装多少水,以1x1方格为单位
     9  *      Answer: 第一次遍历,遍历整个数组,找出最高点
    10  *              第二次遍历,分为两个子遍历最高点左右侧的数组,计算容积
    11  */
    12 
    13 #include <stdio.h>
    14 
    15 /* 宏begin */
    16 /* 宏end */
    17 
    18 /* 输入数据begin */
    19 static const unsigned int WATER_BUCKET[] = { 6, 1, 4, 6, 7, 5, 1, 6, 4 };
    20 /* 输入数据end */
    21 
    22 int main(int argc, char *argv[])
    23 {
    24     int length = sizeof(WATER_BUCKET) / sizeof(unsigned int);
    25     int volume = 0;
    26 
    27     int maxPos = findMaxPos(length);
    28 
    29     volume += countLeftVolume(maxPos);
    30     volume += countRightVolume(length, maxPos);
    31     printf("total volume = %d
    ", volume);
    32 }
    33 
    34 int findMaxPos(int length)
    35 {
    36     int max = 0;
    37     int maxPos = 0;
    38     int i;
    39     for (i = 0; i < length; i++)
    40     {
    41         if (WATER_BUCKET[i] > max)
    42         {
    43             max = WATER_BUCKET[i];
    44             maxPos = i;
    45         }
    46     }
    47 
    48     return maxPos;
    49 }
    50 
    51 int countLeftVolume(int maxPos)
    52 {
    53     int volume = 0;
    54     int leftMax = 0;
    55     int i;
    56     for (i = 0;i < maxPos; i++)
    57     {
    58         if (leftMax >= WATER_BUCKET[i])
    59         {
    60             volume += leftMax - WATER_BUCKET[i];
    61         }
    62         else
    63         {
    64             leftMax = WATER_BUCKET[i];
    65         }
    66     }
    67 
    68     printf("left volume = %d
    ", volume);
    69     return volume;
    70 }
    71 
    72 int countRightVolume(int length, int maxPos)
    73 {
    74     int volume = 0;
    75     int rightMax = 0;
    76     int i;
    77     for (i = length - 1; i > maxPos; i--)
    78     {
    79         if (rightMax >= WATER_BUCKET[i])
    80         {
    81             volume += rightMax - WATER_BUCKET[i];
    82         }
    83         else
    84         {
    85             rightMax = WATER_BUCKET[i];
    86         }
    87     }
    88 
    89     printf("right volume = %d
    ", volume);
    90     return volume;
    91 }

      上述算法也通过了链接中及我自己列举的测试用例,如果大家还有什么更好的解法,欢迎不啬赐教!

  • 相关阅读:
    什么是数据集
    Fastreport使用经验(转)在Delphi程序中访问报表对象
    多步操作产生错误,请检查每一步的状态值
    删除整个目录
    Win7下虚拟机个人使用小结:Virtual PC,VMware和VirtualBox
    Ribbon_窗体_实现Ribbon风格的窗体
    数学建模python matlab 编程(椭圆声学原理画图证明,解析几何)
    数学建模python matlab 编程(指派问题)
    matlab中如何给一个矩阵中的某几个特定位置赋值
    python matlab 带包实现全排列
  • 原文地址:https://www.cnblogs.com/zealotrouge/p/3431471.html
Copyright © 2011-2022 走看看