悠然乱弹:挑战编程极限的问题终于有解了

问题的来历

在群里面一个小萝莉非要说拜我为师,呵呵,对于程序媛我一向--嗯嗯觉得程序不如人好看,再加上该名萝莉大学还没毕业,术语都多半没有听过,于是就想着拒绝,当时嘴一贱,就说了一句:你用一个For循环做个99表出来。

当然,这个对于小萝莉们来说,已经足够形成挑战了,但是对于群里的一众大佬们来说,自然是不在话下,3下5除二就搞定了。我又异想天开一下,如果不用判断语句,是不是也完成呢?粗想想是可以的,于是动手摆了几行代码,确实可以。于是就不断加码,不断增加新的完成条件,于是就形成了下面的问题,挑战极限这个定语,有一定的博眼球的意思,实际上不是那么难了。

挑战极限的问题

今天我想挑战一下OSCHINA的亲们的编程能力,出一道百度、谷歌不到答案的问题,第一个挑战成功的,直接奖励现金100元RMB(本人也是苦B码农,纯属意思一下)。

以前发过一条循环语句打印螺旋矩阵和蛇型矩阵的博客,今天我们来挑战只出现一条循环语句来打印99表。

注意,此题是考思想的,用“*”之外的运算符,如 "&  |  ^  >> << / % "的,虽然确实可以有解,但是代码逻辑与我倡导的:"一个好的算法首先是简单易懂的,其次是清晰明了的,再个一定是充满美感的"是相违背的。为什么下面条件这么多,实在是亲们的创意无限,我防不胜防哦。

特别声明:

  • n可以是任意正整数,只要N的平方不要溢出都可以
  • 一行一行print结果的无效
  • 不允许出现if,switch,?:语句及判断语句的变体,也就是只允许循环变量做条件比较以确定循环次数,不允许其它变量进行条件判断
  • 不允许出现异常
  • 循环语句中只能有一个变量
  • 代码行数超过100行的无效
  • 如果 @红薯 能抢先给出答案,奖金跃升为250元RMB
  • 提交问题并关注本人,回答才有效
  • 答案是否有效解释权归悠然所有

问题如下

不管是什么编程语言,只要是在程序中只用了一条循环语句正确的输出了99表,那么就算挑战成功。

下面是我的测试用例:

测试1:

public static void main(String[] args) {

        new Test99().print(9);

}

运行结果:

 1

 2 4

 3 6 9

 4 8 12 16

 5 10 15 20 25

 6 12 18 24 30 36

 7 14 21 28 35 42 49

 8 16 24 32 40 48 56 64

 9 18 27 36 45 54 63 72 81

测试2:

public static void main(String[] args) {

        new Test99().print(5);

}

运行结果:

 1

 2 4

 3 6 9

 4 8 12 16

 5 10 15 20 25

第一个回答正确的人将获得奖励,以时间为准。

攻城狮的答案

来自各种语言的攻城狮们,对偶的问题进行了长时间的轰炸,有的群大部分时间在讨论这个题有木有?半夜两点继续苦占的有没木有?避木不出的有没有(@红薯 ,别用帽子盖你的脑袋,偶看到你了)?志有必得的有没有(工程的名字就叫GetMoney)?茶不思饭不香,没有思绪加班的有木有?

下面我们就一睹攻城狮们的风采:

利用语言特性搞定的

?


1

2

3

4

5

6

7

8

9

10

11

12

def main(row_count):

    for row_idx in range(1, row_count+1):

        row = map(lambda x:x*row_idx, range(1, row_idx+1))

        print(str(row)[1:-1].replace(",",""))

  

if __name__ == '__main__':

    print("-"*25)

    main(5)

    print("-"*25)

    main(9)

    print("-"*25)

    main(99)

这里有个技巧是 range(1, row_count+1):实际上是利用语言的特性来做了一个循环,不过,确实是非常简练的实现。

相当不错的Java版实现

?


1

2

3

4

5

6

7

8

9

10

11

12

13

<b> public static void print(int n){

            int i = 1;

            int j = 1;

            String flag[] = {"", "\n"};

            while(i <= n){

                System.out.print((i*j) + " ");

                int nextj = (j % i)+1;

                int nexti = (j / i) + i;

                System.out.print(flag[nexti - i]);

                i = nexti;

                j = nextj;

            }

        } </b>

这个实现也是非常不错的,唯一的就是利用了"%  /"小小的违规了一把,而且非常漂亮的把if语句给回避了-实际上是转换成上数组下标了。

依然不错的Java实现

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

<b>public class MultiplicationTable2 {

  

    int line = 1;

    int cursor;

  

    public void print(final int maxLine) {

  

        for (cursor = 1; cursor <= line || enter() <= maxLine; cursor++) {

            System.out.print(cursor * line + "\t");

        }

  

    }

  

    public int enter() {

        System.out.print("\n");

        line++;

        cursor = 1;

        return line;

    }

  

    public static void main(String[] args) {

        new MultiplicationTable2().print(9);

    }

  

}</b>

这个实现的也非常不错,唯一违规的地方是在For语句中夹带了判断语句。

一个for里面搞两个循环变量的

?


1

2

3

4

5

6

7

8

9

<b>for (int i = 1, j = 1; j <= 9; i++)

    {

     System.out.printf("%d*%d=" + i * j + " ", i, j);

     if (i == j) {

      i = 0;

      j++;

      System.out.println();

     }

    } </b>

当然,里面还多一个if判断

一不小心用了两个For的解法 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

package everydaydo;

 

 

public class OSC {

 

 

public static void main(String[] args) {

OSC.fun1(9);

}

 

 

public static void fun1(int n){

StringBuilder sb = new StringBuilder();

for(int i=1;i<=n;i++){

sb.append(fun2(i));

}

System.out.println(sb.toString());

}

 

public static String fun2(int m){

StringBuilder sb = new StringBuilder();

for(int i=1;i<=m;i++){

sb.append(i*m+"\t");

}

sb.append("\n");

return sb.toString();

}

}

有把历史实现直接过过冲奖的

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

class MulTable{

    public enum MulTableEnum{

        ASC,

        DESC

    }

    public void showMulTable(final int count, MulTableEnum e){

        if(MulTableEnum.ASC == e){

            ascMulTable(count);

        }else{

            descMulTable(count);

        }

    }

    private void descMulTable(final int count){

        if(count<1){

            i=0;

            return;

        }

        if(i!=count){

            i++;

            System.out.print(i+"*"+count+"="+i*count+"\t");

            descMulTable(count);

        }else{

            i=0;

            System.out.println();

            descMulTable(count-1);

        }

    }

    private void ascMulTable(final int count){

        if(j>count){

            j=1;

            return;

        }

        if(i!=j){

            i++;

            System.out.print(i+"*"+j+"="+i*j+"\t");

        }else{

            i=0;

            j++;

            System.out.println();

        }

        ascMulTable(count);

    }  

    private int i=0;

    private int j=1;

}

public class Test {

  

    /**

     * @param args

     */

    public static void main(String[] args) {

        // TODO Auto-generated method stub

        MulTable mul = new MulTable();

        mul.showMulTable(9, MulTable.MulTableEnum.DESC);

        mul.showMulTable(9, MulTable.MulTableEnum.ASC);

    }

  

}

亲,你这题目也不仔细看看,怎么可能对得上要求呢?

Java版递归来了

?


1

2

3

4

5

6

7

8

9

10

11

12

public void show(int n){

        if (n == 0) {

            return ;

        }else{

            show(--n);

        }

        for(int i = 1; i <= n ; i++){

            System.out.print(i*n + " ");

        }

        System.out.println();

          

    }

唯一的就是用了if语句,唉,楼上的那位兄弟,你那递归和这个相比,是不是有点偏Low了?

某攻城狮的再战作品

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

public class asdfasf {

  

    public static void main(String[] args) {

        int n = 9;

        int i = 1;

        int line = 1;

        int lastSq = 0;

        while (i <= n * n) {

            System.out.print(i + " ");

            int sq = (int) Math.sqrt(i);

            if (sq * sq == i && sq > lastSq) {

                line++;

                System.out.println();

                i = line;

                lastSq = sq;

            } else {

                i = i + line;

            }

        }

    }

  

}

这个代码可读性稍差一点,当然,里面有if判断,违规了

JavaScript版来了

我们的前端攻城狮也不甘寂寞,冲上来了

?


1

2

3

4

5

6

7

8

9

10

11

12

13

$(document).ready(function () {

            $("body").html(Print(5));

        });

        var PrintHtml = "";

        function Print(num) {

            var ThisHtml = "";

            for (var i = 1; i <= num; i++) {

                ThisHtml += (i * num).toString() + "&nbsp;&nbsp;";

            }

            PrintHtml = ThisHtml + "<br>" + PrintHtml;

            (num - 1) > 0 ? Print((num - 1)) : PrintHtml;

            return PrintHtml;

        }

嗯嗯,用了?:

某大神的第三次冲刺

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

public class asdfasf {

  

  

 public static void main(String[] args) {

 int n = 9;

 n = n * n;

 int i = 1;

 int line = 1;

 int times = line;

 while (i <= n) {

 System.out.print(i + " ");

  

  

 times = times - 1;

 try {

 System.out.println(1 / times);

 i = i + line;

 } catch (Exception e) {

 line++;

 times = line;

 i = line;

 System.out.println();

 }

  

 }

 }

  

}

这次居然用了反人类的异常来替换IF,确实是让我大大吃了一斤,亲我给归到使用if变体里了。

JavaScript再战

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

$(document).ready(function () {

            Print(5);

            $("body").html(PrintHtml);

        });

        var PrintHtml = "";

        function Print(num) {

            var ThisHtml = "";

            for (var i = 1; i <= num; i++) {

                ThisHtml += (i * num).toString() + "&nbsp;&nbsp;";

            } PrintHtml = ThisHtml + "<br>" + PrintHtml;

            while ((num - 1) > 0) {

                Print(num - 1);

                num = 0;

            }

        }

嗯嗯,用了两个循环

一个距离成功只有一步之遥的答案

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

public class Test99 {

    public static void main(String[] args) {

        Test99.print(20);

    }

 

    private static void print(int n) {

        for (int i = 1; i <= n; i++) {

            print2(i);

        }

    }

 

    private static void print2(int k) {

        for (int i = 1; i <= k; i++) {

            System.out.print(i * k + " ");

        }

        System.out.println();

    }

}

这个答案,实际上熟悉模式的同学,大致看看就能想出怎么把两个for语句干掉一个的办法,可惜了一点儿。

实践比想法困难的代表

某大神第4次挑战

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

public class MultiplicationTable {

  

    public static void main(String[] args) {

  

        char space = ' ';

        char enter = '\n';

  

        int n = 9;

  

        int i = 1;

        int line = 1;

        int col = 0;

        int current = 1;

        while (i <= (1 + n) * n / 2) {

            System.out.print(current);

  

            // col = col + 1;

            int isZero = ((line - col - 2) >> 31 & 1);

  

            line = line + 1 * isZero;

            col = (col + 1) - (col + 1) * isZero;

            current = line + current + (-current) * isZero;

            System.out.print((char) (space + (enter - space) * isZero));

            i++;

        }

  

    }

  

}

嗯嗯,里面有/有>>有&,总之各种小技巧。偶的答复:

亲,我觉得一个好的算法,首先是简单的,再一个是容易理解的,再一个是有技巧的。 

中间省略N个重复了的代码

C#版的来了

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

#include <iostream>

using namespace std;

  

typedef void (*pFun)(int m, int k);

  

void f0(int m, int k)

{

    cout<<endl;

}

  

void f1(int m, int k)

{

    pFun fun[2] = {f0, f1};

    cout<<m * k<<" ";

    fun[(k<m)](m, k+1);

}

  

void printLine(int m)

{

    f1(m, 1);

}

  

void run(int m)

{

    int i = 1;

    while (i <= m)

    {

        printLine(i);

        i++;

    }

}

  

int main()

{

    run(9);

    return 0;

}

里面用到了k<m判断语句

SCALA版来了

?


1

2

3

def mul(n: Long): String = (1L to n).map { i =>

  (1L to i).map(_ * i).mkString(" ")

}.mkString(System.getProperty("line.separator"))

太精练了!!!就是那to了两次是不是两个循环?

非常不错的实现

?


1

2

3

4

5

6

7

8

9

10

def test99(n):

    i = 1

    j = 1

    while i <= n:

        print '%d ' % (i * j),

        nj = (j % i) + 1

        ni = (j / i) + i

        print '\n' * (ni - i),

        i = ni

        j = nj

唯一就是小小的违规了。

这是啥语言版来着?

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

package object test {

  def main(args: Array[String]) {

    _99(9)

  }

  

  def _99(m: Int) {

    var i = 1;

    while (i <= m) {

      printLine(i);

      i += 1

    }

  }

  

  def printLine(m: Int) {

    printResult(m, 1);

  }

  

  def printResult(m: Int, k: Int) {

    print(m * k + "\t")

    matchResult(m - k > 0, m, k);

  }

  

  def matchResult(in: Any, m: Int, k: Int) = in match {

    case true => printResult(m, k + 1)

    case _ => println()

  }

  

}

里面有判断语句。

JavaScript版的解法

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

/**

javascript 版, chrome 浏览器, CTRL+SHIFT+I 打开调试器 -> console选项卡 粘贴代码并回车:

  

**/

function _99x(n){

    function iterate(n, callback){

        for(var idx = 1; idx <= n; idx++)

            callback(idx, n);

    }

    iterate(n, function(start, end){

        iterate(start, function(start, end){

            console.log(start * end);

        })

        console.log('-------')

    })

}

原来没有仔细看,以为callback是系统函数,今天仔细看,原来这个是OK的,唯一的问题是换行怎么处理的?

NIM版

?


1

2

3

4

5

6

7

8

## test.nim

  

for i in 1..9:

    for j in 1..i:

        write stdout, j * i

    write stdout, '\10'

  

## $ nim c -r test.nim

呵呵,标准的就是这么写的。

这个是啥版?

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

proc p(n: int) =

    proc walki(j: int, i: int) =

        if j <= i:

            write(stdout, j * i)

            walki(j + 1, i)

        else:

            write(stdout, '\10')

  

    proc walk(i: int) =

        if i <= n:

            walki(1, i)

            walk(i + 1)

    walk(1)

  

p(9)

明显有判断了。

C语言版来了

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

#include <stdio.h>

  

//输出一行

int print_one_row(int i, int n)

{

        return (i <= n) && ((printf("%d ", i*n), print_one_row(i+1, n)));

}

  

//整体输出

int print_all(int n)

{

        return (n && (print_all(n-1), print_one_row(1, n), printf("\n")));

}

  

int main(int argc, char *argv[])

{

        print_all(1); //测试1行

        print_all(9); //测试9行

        print_all(11); //测试11行

        return 0;

}

用了if变体

也不是错的实现

?


1

2

3

4

5

6

7

8

9

10

11

import sys, math

  

def test99(a):

    for i in xrange((1 + a) * a / 2):

        i = i + 1

        q = int(math.sqrt(i * 2))

        b = q * (q + 1) / 2 - i       

        sys.stdout.write(str(max(q * -b + -b, q * -b + q * q)))           

        sys.stdout.write(chr(10 - max(abs(b), 0) / max(abs(b), 1)))

          

test99(5)

这个性能确实有点差的,sqrt,* / max 好多运算哦

号称邪恶的解法

一个变量是挡不住邪恶的我的, 你是不是要考虑限制内存的使用?

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

package com.test;

   

   

public class Test99 {

       

    public void print(Integer... oneVar){

        oneVar = new Integer[]{oneVar[0], 1, 1};

        while(oneVar[1]<=oneVar[0]

                && System.out.printf(oneVar[1]*oneVar[2]+"\t")!=null

                &&((oneVar[1] == oneVar[2] && (oneVar[1]++>0 && System.out.printf("\n")!=null) && (oneVar[2]=0)==0) || true)

                ){

            oneVar[2]++;

        }

    }

   

}

简单的说,是把判断隐藏在while里了。

超级技巧版来了

?


1

2

3

4

5

6

7

function fun(n){

    (n - 1) && fun(n - 1);

    for(var idx = 1; idx <= n; idx++)

        process.stdout.write(idx * n + ' ')

    process.stdout.write('\n')

}

fun(process.argv[2]);

这里的技巧相当高明,隐藏得非常深。

C# 简短版

?


1

2

3

4

5

6

7

8

9

10

11

12

static int s = 9;

        public static void print(int k=1)

        {

            int m = 1;

            while (m <= k && k <= s)

            {

                Console.Write("{0}*{1}={2}\t", m, k, m * k);

                m++;

            }

            Console.WriteLine();

            if(m<=s) print(m);

        }<span></span>

C#版的,想来想去都要一个if来判断边界啊。

==嗯嗯,如果有一个if,这题就不难了:)

世界上最好的语言PHP版也来了

?


1

2

3

4

5

6

7

8

9

10

<?php

//生成1-9的数组,我只是快速定义好数组..这不算循环吧。23333

$number = range(1, 9);

//数组递归..

array_walk($number, function($param, $key) {

    for ($i = 1; $i < $key + 2; $i++) {

        echo $param * $i. " ";

    }

    echo '<br/>';

});

range函数是干啥的,里面有没有个循环语句帮你干活?

版本帝的第N版来了

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

public class MultiplicationTable3 {

  

    /**

     * 主要是使用了数组初始化后,未赋值的位置为0,来实现复位的效果。<br>

     * cursors数组运行中第一位总是0,变化过程如:<br>

     * {0,0,0,0,0,0,0,0,0}<br>

     * {0,1,0,0,0,0,0,0,0}<br>

     * {0,1,2,0,0,0,0,0,0}<br>

     * {0,1,2,3,0,0,0,0,0}<br>

     *

     * @param n

     */

    public void print(final int n) {

        // 游标控制,多一位,容错

        int[] cursors = new int[n + 1];

        // 基数,系数

        int[] factor = new int[n];

        factor[0] = 1;

  

        // 字符后缀

        char[] suffixChars = new char[n];

        suffixChars[0] = '\n';

  

        int i = 0;

  

        while (factor[0] <= n) {

            int colValue = (cursors[i] + 1);

            System.out.print(colValue * (factor[0]) + " ");

  

            int temp = i;

            i = cursors[i + 1];

            cursors[temp + 1] = cursors[temp] + 1;

            factor[i] = factor[i] + 1;

  

            System.out.print(suffixChars[i]);

  

        }

  

    }

  

    public static void main(String[] args) {

        new MultiplicationTable3().print(9);

    }

  

}

JS版改进型

这里的undefined:部分是不是判断的变体呢?

多线程版来了

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

public class Test99 {

    private int rowNum;

    private int[] arr;

    private int i;

    public Test99(int rowNum, int[] arr, int i) throws InterruptedException {

        this.rowNum = rowNum;

        //初始化一个长度为N+1的数组,如rowNum=5,数组为[0,0,0,0,0,0]

        this.arr= arr;

        this.i = i;

        try {

            arr[i+1] = arr[i] + 1;

            PrintThread printThread = new PrintThread(arr[++i], rowNum);

            printThread.start();

            new Test99(rowNum, arr, i);

        }

        catch (Exception e) {

            Thread.sleep((arr[--i] + 1) * 100);

            Thread.interrupted();

        }

    }

}

  

class PrintThread extends Thread {

    int length = 0;

    int rowNum = 0;

    public PrintThread (int length, int rowNum) {

        this.length = length;

        this.rowNum =rowNum;

    }

    @Override

    public void run() {

        try {

            Thread.sleep(length * 100);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        for (int i = 1; i <= length; i++) {

            System.out.print(i * length + "\t");

        }

        System.out.println();

    }

}

居然有线程,居然有异常,偶的心好凌乱....让偶缕缕

韦达定理版

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

public class Test99 {

    public void print(int n) {

        for (int i = 0; i < n * (n + 1) / 2; i++) {

            int row = (int)((Math.sqrt(1 + 8 * i) - 1) / 2);

            int column = i - row * (row + 1) / 2;

            int end = 10 + (int)Math.ceil(1.0 * (row - column) / (row + 1)) * 22;

            System.out.printf("%d%c", (row + 1) * (column + 1), end);

        }

    }

  

    public void printOneline(int n) {

        for (int i = 0; i < n * (n + 1) / 2; i++) {

            System.out.printf("%.0f%c", (Math.floor((Math.sqrt(1 + 8 * i) - 1) / 2) + 1) * (i - Math.floor((Math.sqrt(1 + 8 * i) - 1) / 2) * (Math.floor((Math.sqrt(1 + 8 * i) - 1) / 2) + 1) / 2 + 1), (int)(10 + (int)Math.ceil(1.0 * (Math.floor((Math.sqrt(1 + 8 * i) - 1) / 2) - i + Math.floor((Math.sqrt(1 + 8 * i) - 1) / 2) * (Math.floor((Math.sqrt(1 + 8 * i) - 1) / 2) + 1) / 2) / (Math.floor((Math.sqrt(1 + 8 * i) - 1) / 2) + 1)) * 22));

        }

    }

  

    public static void main(String[] args) {

        new Test99().print(5);

        new Test99().printOneline(9);

    }

}

亲,但是不允许用/,而且这个性能也太慢了........

至尊版来了,此版一出,天地为之变色,世人为之瞩目

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

data segment

a db 1

b db ?

data ends

code segment

assume cs:code,ds:data

start:mov ax,data

mov ds,ax 

lop1:

mov al,a 

mov cl,al 

  

mov b,1

lop:

mov ah,2 

or b,30h

mov dl,b 

int 21h 

  

mov dl,'*'

int 21h

  

or a,30h 

mov dl,a

mov ah,2

int 21h

  

mov dl,'='

int 21h

  

sub a,30h

sub b,30h 

mov al,a

  

mov bl,b

mul bl

mov bl,10

div bl 

mov bh,al

mov bl,ah

or bx,3030h

  

  

mov ah,2

cmp bh,30h 

je lop2 

mov dl,bh 

int 21h

lop2:

mov dl,bl 

int 21h

  

mov dl,' '

int 21h

inc b 

loop lop

  

mov dl,13

int 21h

mov dl,10

int 21h

  

inc a

cmp a,10

jb lop1 

  

mov ah,4ch

int 21h

code ends

end start

破绽在这里 cmp bh,30h je lop2

尽管你换了个马甲,照样认识你。

正解来了

?


1

2

3

4

5

6

7

8

9

10

11

12

function _99x(n){

    function iterate(n, callback){

        for(var idx = 1; idx <= n; idx++)

            callback(idx, n);

    }

    iterate(n, function(start, end){

        iterate(start, function(start, end){

            process.stdout.write(start * end + ' ');

        });

        process.stdout.write('\n');

    })

}

作者自述:

我第一次写的这个实际上跟此答案思路相似,都是模板方法,横向或纵向都是遍历, 不同的是遍历过程中的处理逻辑(一个是算乘积, 另一个是输出换行以及启动横向遍历过程), 实质上就是把循环逻辑抽取出来(比如一个叫"遍历器"或者叫"遍历模板"的东西), 留个回调方法, 做不同的逻辑处理,如果此题通过,我写的也算通过了

说白了,就是模板模式的应用。 

悠然的解法

悠然的解法,说实际的,只花了几分钟的时间考虑,写了一个,估计已经算不得最优解了。当时我和群里的同学们有说过:如果我最后拿不出来一个解,估计被一干人等骂死了。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

public class Test99 {

    public static void main(String[] args) {

        Iterator.iterate(5,new IAction());

    }

}

abstract class Iterator<T> {

    abstract void process(T n);

    static void iterate(int n, Iterator action) {

        for (int i = 1; i <= n; i++) {

            action.process(i);

        }

    }

}

class IAction extends Iterator<Integer> {

    public void process(Integer n) {

        iterate(n, new JAction(n));

        System.out.println();

    }

}

class JAction extends Iterator<Integer> {

    private final int x;

    JAction(int n) {

        this.x = n;

    }

    public void process(Integer n) {

        System.out.print(" "+x * n);

    }

}

解题思路解释:

实际上,只用一个For语句打印99表,无非是以下几种方案:

  1. 一个循环语句来完成:这种方案肯定需要一些其它指令来配合,比如/ % sqrt等等,同时换行符处理也非常难处理,如果没有IF的话,是非常难以解决的。
  2. 递归方式:递归方式一般来说肯定需要有退出条件判断,否是就变成死循环了
  3. 把一个For语句使用两次

再来看看我的注意事项:

注意,此题是考思想的,用“*”之外的运算符,如 "&  |  ^  >> << / % "的,虽然确实可以有解,但是代码逻辑与我倡导的:"一个好的算法首先是简单易懂的,其次是清晰明了的,再个一定是充满美感的"是相违背的。为什么下面条件这么多,实在是亲们的创意无限,我防不胜防哦。

这里,所有的限制都是为了把攻城狮向第3种方案逼,同时里面也有提醒:是考思想的。

接下来解释一下我的代码:

  • Iterator是一个迭代类,它的功能就是去做循环,然后干它应该干的事情,实际上为重用For语句埋好了伏笔。
  • IAction用于完成ForFor实现方式的第一层循环,从语义上来讲就是打印每一行的内容,然后换行
  • JAction用于完成ForFor实现方式的第二层循环,输出每行的计算式

里面没有任何和判断相关的代码,里面只出现了一次For循环语句,同时也没有乱七八糟的其它运算符和库函数。

代码扣除测试相关代码,也就是20行代码左右。

实际上,这个时候与上面说的正解的解法对比,仅仅是由于语言的特性导致的实现形式不一样而已,实际上思想是完全一致的。

大结局

感谢所有参与此项挑战的同学,不管你们采用的是什么语言,不管你们的方法是不是挑战成功,你们都是成功的,你们对自己的极限的挑战,对未知世界的探索的精神都是我学习的榜样。限于篇幅,有些同学的答案没有贴上来,在此表示歉意。

同时,对于我们来说,也有非常大的收获:

  1. 要敢于对我们已经习惯的方式进行挑战:有时候,我们已经习惯于遵守习惯,却丧失了打破习惯的勇气
  2. 知道不代表拥有:如果直接告诉你这个是应用什么什么模式来解决的,我想大多数的同学都是知道的,也是可以搞得定,但是只有想用就能用得出来的东西才是自己的。
  3. 群众们的表现,所有的参与者都学到了许多许多,再一次认识到自己的渺小,所以不要相信自己是最NB的几乎永远是对的。    

实际上,在这次挑战活动的收益最大的正是我自己,再次感谢所有同学,尤其是@红薯 为了我们搭建了这么好的平台,对了那100块奖金能不能给报销了?

时间: 2025-01-11 17:28:28

悠然乱弹:挑战编程极限的问题终于有解了的相关文章

悠然乱弹:螺旋矩阵和蛇型矩阵的悠然版实现

螺旋矩阵和蛇型矩阵,是两个比较有趣的矩阵,有许多的公司面试题中有出现,这两个题的答案也有许多种,简单问一下度娘,就各自有N种实现,来源也非常丰富,比如CSDN.ITEYE.等等,当然也包括著名的OSC,但是整体看下来,呵呵,比较顺眼的比较少,比较经典的就越发少了. 考虑到不同的语言有不同的语言特性,因此今天就只用Java来进行实现,看看螺旋矩阵和蛇型矩阵的悠然版实现,让我们的OSC也更加高大上一些,. 概念说明 什么是螺旋矩阵 螺旋矩阵是指一个呈螺旋状的矩阵,它的数字由第一行开始到右边不断变大,

VMware 虚拟化编程(7) — VixDiskLib 虚拟磁盘库详解之三

目录 目录 前文列表 VixDiskLib 虚拟磁盘库 VixDiskLib_GetMetadataKeys VixDiskLib_ReadMetadata 获取虚拟磁盘元数据 VixDiskLib_WriteMetadata 更新虚拟磁盘元数据表 VixDiskLib_Create 创建新的寄宿磁盘 Hosted Disk VixDiskLib_Clone 克隆 VMDK File 创建新的托管磁盘 Managed Disk VixDiskLib_Unlink 删除 VMDK File Vix

VMware 虚拟化编程(5) — VixDiskLib 虚拟磁盘库详解之一

目录 目录 前文列表 VixDiskLib 虚拟磁盘库 虚拟磁盘数据的传输方式 Transport Methods VixDiskLib_ListTransportModes 枚举支持的传输模式 VixDiskLib_InitEx 初始化 VixDiskLib 库 VixDiskLib_ConnectEx 连接到 virtual disk library VixDiskLib_Disconnect 断开 VixDiskLib 的连接 VixDiskLib_Cleanup 断开连接之后的清理 Vi

Python黑帽编程 3.4 跨越VLAN详解_python

VLAN(Virtual Local Area Network),是基于以太网交互技术构建的虚拟网络,既可以将同一物理网络划分成多个VALN,也可以跨越物理网络障碍,将不同子网中的用户划到同一个VLAN中.图2是一个VLAN划分的例子. 图2 实现VLAN的方式有很多种,基于交换设备的VLAN划分,一般有两种: l 基于交换机的端口划分 l 基于IEEE 802.1q协议,扩展以太网帧格式 基于第二层的VLAN技术,有个Trunking的概念,Trunking是用来在不同的交换机之间进行连接,以

悠然乱弹:从几个方法的重构讲开去--性能大优化

现在还存在多次扫描处理的问题,也就是说虽然代码结构性重构是成功的,但是性能问题还是没有根本解决. 在给出解决方案之前,需要对这个处理方式缕一缕: 处理方式1:每次遍历全路径找到待处理文件,文件然后批量进行处理.优点是处理起来比较简单,但是会重复扫描. 处理方式2:一次遍历所有文件,然后对每个文件进行注解检测.扫描全路径只有一次,然后要把每个文件与过滤器进行比较如果比较成功那就做,比较不成功就不做. 稍加分析就会发现,两种方式的比较次数是一样的,但是第二种方案遍历文件的次数就少到极限了,还能比1次

悠然乱弹:拉钩网FizzBuzzWhizz试题之悠然版解答

试题 ? 1 2 3 4 5 6 7 你是一名体育老师,在某次课距离下课还有五分钟时,你决定搞一个游戏.此时有100名学生在上课.游戏的规则是:   1. 你首先说出三个不同的特殊数,要求必须是个位数,比如3.5.7. 2. 让所有学生拍成一队,然后按顺序报数. 3. 学生报数时,如果所报数字是第一个特殊数(3)的倍数,那么不能说该数字,而要说Fizz:如果所报数字是第二个特殊数(5)的倍数,那么要说Buzz:如果所报数字是第三个特殊数(7)的倍数,那么要说Whizz. 4. 学生报数时,如果所

悠然乱弹:如何正确看待加入Tiny团队先从测试用例编写和文档编写开始?

有一个同学,问我一个问题:加入Tiny是否必须从写单元测试用例和文档作起? 此问题引发我诸多感触,故形成乱弹一篇. 作为一个新加入者,多看.少说,是正点.而这个时候,写写测试用例.文档,就是个不错的选择.这样入手比较容易,也比较容易体现水平. 可以说好的程序员,测试和文档都是写得好的.测试和文档一定写不好的,一定不是好的程序员.  同时,在看代码,写测试用例.写文档的过程中,还可以这样思考: 他为什么要这么设计?换成我,我会怎么设计?然后有相当一部分,会转化成:哦,原来是这个样子的!这个时候你进

Google内部头脑风暴出来的广告赚钱计划 挑战隐私极限

中介交易 SEO诊断 淘宝客 云主机 技术大厅 华尔街日报拿到了一份号称是Google内部备忘录的文件,该文件描述了公司未来的赚钱渠道展望,其中主要描绘的赚钱渠道主要集中在用户隐私数据交换和广告方面,其中一些想法几乎在挑战人类隐私极限,比如: Get Paid:用户可以选择加入这个Get Paid项目,通过分享他们所有用户数据来得到ISP宽带服务商的优惠价格或是某种形式的返点.用户信息的正确性可以经第三方验证,比如提供他们的信用卡交易记录来验证性别.收入状况.所在地等信息,或者通过Amazon来

双十一挑战技术极限,阿里云计算支撑912.17亿商业奇迹

阿里巴巴集团披露,双十一当天系统交易创建峰值达到每秒钟14万笔,支付峰值达到每秒钟8.59万笔.相比2009年首届双十一,订单创建峰值增长了350倍,支付峰值增长了430倍. 据天猫方面透露,零点钟声一过,短短的12分零28秒,天猫的销售额就突破了百亿人民币.可想而知,这种瞬间爆发式的交易量对于电商平台来说无疑是一种巨大的考验,而此时,强大坚挺的云计算平台无疑是不二之选. 与各大物流公司的严阵以待相比,流量爆发对企业线上能力的考验更像是一场看不见的技术竞赛.11月10日,记者从阿里云获悉,除了天