乐趣区

关于算法:算法笔试骗分套路

我晓得各位是被题目吸引进来的,那就不废话,先说几个算法口试的硬核套路,再说说做题温习的策略。

就事论事

大家也晓得,大部分口试题目都须要你本人来解决输出数据,而后让程序打印输出。判题的底层原理是,把你程序的输入用 Linux 重定向符 > 写到文件外面,而后比拟你的输入和正确答案是否雷同。

那么有的问题难点就变得形同虚设,咱们能够偷工减料,举个简化的例子,假如题目说给你输出一串用空格分隔的字符,通知你这代表一个单链表,请你把这个单链表翻转,并且强调,肯定要把输出的数字转化成单链表之后再翻转哦!

那你怎么做?真就本人定义一个 ListNode 单链表节点类,而后再写代码把输出转化成一个单链表,而后再用让人头晕的指针操作去老老实实翻转单链表?

搞清楚咱们是来 AC 题目的,不是来学习算法思维的。正确的做法是间接把输出存到数组里,而后用 双指针技巧 几行代码给它翻转了,而后打印进去完事儿。

我就见过不少这种题目,比方题目说输出的是一个单链表,让我分组翻转链表,而且还特别强调要用递归实现,就是咱们旧文 K 个一组翻转链表 的算法。嗯,如果用数组进行翻转,两分钟就写进去了,嘿嘿。

还有咱们前文 扁平化嵌套列表 讲到的题目,思路很奇妙,然而在口试中遇到时,输出是一个形如 [1,[4,[6]]] 的字符串,那间接用正则表达式把数字抽出来,就是一个扁平化的列表了……

巧用随机数

再说一个鸡贼的技巧,留神那些输入为「二值」的题目,二值就是相似布尔值,或者 0 和 1 这种组合无限的。

比如说很多题目是这样,巴拉巴拉给你说一堆条件,而后问你输出的数据能不能达成这些条件,如果能的话请输入 YES,不能的话输入 NO

如果你会做当然好,如果不会做怎么办?

首先这样提交一下:

public class Main {public static void main(String[] args) {System.out.println("YES");
    }
}

看下 case 通过率,假如是 60%,那么阐明后果为 YES 有 60% 的概率,所以能够这样写代码:

public class Main {public static void main(String[] args) {
        // 60% 的概率输入 YES,40% 的概率输入 NO
        System.out.println((new Random().nextInt() % 100) < 60 ? "YES" : "NO");
    }
}

嘿嘿,labuladong 说了,这题你能够不会,然而肯定要在力不从心的范畴内做到极致!

概率巨匠

说一个场景,如果口试呈现那种恶心人的单选,四个选项全都没见过,而后你蒙了一个 C。

假如,过了一会你忽然灵光一闪,唤起一些系统的记忆,确定 B 选项是错的,那么,这时候你该怎么做?

从新在 A 和 D 两头蒙一个啊哥哥!不从新蒙,正确的概率是 1/4,从新蒙,正确的概率是 3/8,白捡的概率都不要么?

是不是感觉不堪设想?是不是感觉我在胡扯?

这样,假如一道选择题有 100 个选项,你轻易蒙一个,正确率为 1%,错误率为 99%。

假如当初 labuladong 显灵,帮你在剩下的 99 个选项中排除了 98 个谬误选项,只剩下一个选项,而后问你,你持续保持原来的抉择,还是换成帮你排除剩下的那个选项?

换啊!换了之后正确概率是 1 – 1% = 99% 啊!

那如果 labuladong 只帮你排除了 90 个谬误选项,剩下 9 个选项,那你要不要换成这 9 个选项中的某一个?

换啊!换了之后正确概率是 (1 – 1%) / 9 = 11% 啊!

那回过来看,四个选项,你开始蒙了一个,起初灵光一闪在剩下三个选项中排除了一个谬误答案,那你换不换?

换啊!换了之后正确概率是 (1 – 1/4) / 2 = 3/8 啊!

其实这就是典型的「三门问题」,不晓得的话看旧文 几个反直觉的概率问题。

编程语言的抉择

仅从做算法题的角度来说,我集体比拟倡议应用 Java 作为口试的编程语言。因为 JetBrain 家的 IntelliJ 切实是太香了,相比其余语言的编辑器,不仅有 psvmsout 这样的快捷命令(你要是连这都不晓得,连忙面壁去),而且能够帮你查看出很多笔误,比如说 while 循环外面遗记递增变量,或者 return 语句错写到循环里这种因为忽略所导致的问题。

C++ 也还行,然而我感觉没有 Java 好用。我印象中 C++ 连个宰割字符串的 split 函数都没有,光这点我就不想用 C++ 了……

还有一点,C++ 代码对工夫的限度高,别的语言工夫限度 4000ms,C++ 限度 2000ms,我感觉挺吃亏的。怪不得看他人用 C++ 写算法,为了进步速度,都不必规范库的 vector 容器,非要用原始的 int[] 数组,我看着都头疼。

Python 的话我刷题用的比拟少,因为我不太喜爱用动静语言,不好调试。不过这个语言的奇技淫巧太多,如果你深谙 Python 的套路,能够在某些时候投机取巧。比如说咱们前文写到的 表达式求值算法 是一个艰难级别的算法,但如果用 Python 内置的 exec 函数,间接就能算出答案。

这个在口试里必定是很占便宜的,因为之前说了,咱们要的是后果,没人在乎你是怎么失去后果的。

解法代码分层

代码分层应该算是一种比拟好的习惯,能够减少写代码的速度和升高调试的难度。

简略说就是,不要把所有代码都写在 main 函数外面,我始终应用的套路是,main 函数负责接收数据,加一个 solution 函数负责对立解决数据和输入答案,而后再用诸如 backtrack 这样一个函数解决具体的算法逻辑。

举个例子,比如说一道题,我决定用带备忘录的动静布局求解,代码的大抵构造是这样:

public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);
        // 次要负责接收数据
        int N = scanner.nextInt();
        int[][] orders = new int[N][2];
        for (int i = 0; i < N; i++) {orders[i][0] = scanner.nextInt();
            orders[i][1] = scanner.nextInt();}
        // 委托 solution 进行求解
        solution(orders);
    }

    static void solution(int[][] orders) {
        // 排除一些根本的边界状况
        if (orders.length == 0) {System.out.println("None");
            return;
        }
        // 委托 dp 函数执行具体的算法逻辑
        int res = dp(orders, 0);
        // 负责输入后果
        System.out.println(res);
    }

    // 备忘录
    static HashMap<String, Integer> memo = new HashMap<>();
    static int dp(int[][] orders, int start) {// 具体的算法逻辑}
}

你看这样分层是不是很分明,每个函数都有本人次要负责的工作,如果哪里出了问题,你也容易 debug。

倒不是说要把代码写得多标准,至于 private 这种束缚免了也不妨,变量用拼音命名也 OK,要害是别把代码间接全写到 main 函数外面,真的乱,不出错也罢,一旦出错,预计要花一番功夫调试了,找不到问题乱了阵脚,那是要尽量避免的。

考前温习策略

考前就别和某一道算法题死磕了,不划算。

应该尽可能多的看各种各样的题目,思考五分钟,想不进去解法的话间接看他人的答案。看懂思路就行了,甚至本人写一遍都没必要,因为比拟浪费时间。

口试的时候最怕的是没思路,所以把各种题型都过目一下,起码心里不会慌,只有有思路,均匀一道题二三十分钟搞定还是不难的。

后面不是说了么,没有什么问题是暴力穷举解决不了的,间接用 回溯算法套路框架 硬上,大不了加个备忘录,不就成 动静布局套路框架 了么,再大不了这题我不做了么,暴力过上 60% 的 case 也挺 OK 的。

别的不多说了,套路这个货色,说来简略,一点就透,但问题是不点就不透。本文我简略介绍了几个口试算法的技巧,各位好好品尝~

退出移动版