HZ 偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计
算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的
正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为 8(从第 0 个开始,到第 3 个为止)。你会不会被他忽悠
住?(子向量的长度至少是 1)
思路:
(1)第一种思路是直接暴力求解的方式,先以第一个数字为首往后开始叠加,叠加的过程中保存最大的值。然后再以第二个数字为首
往后开始叠加,并与先前保存的最大的值进行比较。这一种方法的时间复杂度为 O(n^2)。
(2)第二种思路是,首先我们观察一个最大和的连续数组的规律,我们可以发现,子数组一定是以正数开头的,中间包含了正负数。
因此我们可以从第一个数开始向后叠加,每次保存最大的值。叠加的值如果为负数,则将叠加值初始化为 0,因为后面的数加上负
数只会更小,因此需要寻找下一个正数开始下一个子数组的判断。一直往后判断,直到这个数组遍历完成为止,得到最大的值。
使用这一种方法的时间复杂度为 O(n)。
详细资料可以参考:
《连续子数组的最大和》
31. 整数中 1 出现的次数(待深入理解)
=======================
题目:
求出 1~13 的整数中 1 出现的次数,并算出 100~1# 300 的整数中 1 出现的次数?为此他特别数了一下 1~13 中包含 1 的数字有 1、10、11、
12、13 因此共出现 6 次,但是对于后面问题他就没辙了。ACMer 希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整
数区间中 1 出现的次数。
思路:
(1)第一种思路是直接遍历每个数,然后将判断每个数中 1 的个数,一直叠加。
(2)第二种思路是求出 1 出现在每位上的次数,然后进行叠加。
详细资料可以参考:
《从 1 到 n 整数中 1 出现的次数:O(logn)算法》
32. 把数组排成最小的数
==============
题目:
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321
},则打印出这三个数字能排成的最小数字为 321323。
思路:
(1)求出数组的全排列,然后对每个排列结果进行比较。
(2)利用排序算法实现,但是比较时,比较的并不是两个元素的大小,而是两个元素正序拼接和逆序拼接的大小,如果逆序拼接的
结果更小,则交换两个元素的位置。排序结束后,数组的顺序则为最小数的排列组合顺序。
详细资料可以参考:
《把数组排成最小的数》
33. 丑数(待深入理解)
==============
题目:
把只包含质因子 2、3 和 5 的数称作丑数。例如 6、8 都是丑数,但 14 不是,因为它包含因子 7。 习惯上我们把 1 当做是第一个丑数。求
按从小到大的顺序的第 N 个丑数。
思路:
(1)判断一个数是否为丑数,可以判断该数不断除以 2,最后余数是否为 1。判断该数不断除以 3,最后余数是否为 1。判断不断除以
5,最后余数是否为 1。在不考虑时间复杂度的情况下,可以依次遍历找到第 N 个丑数。
(2)使用一个数组来保存已排序好的丑数,后面的丑数由前面生成。
34. 第一个只出现一次的字符
================
题目:
在一个字符串(1<=字符串长度<=10000,全部由大写字母组成)中找到第一个只出现一次的字符,并返回它的位置。
思路:
(1)第一种思路是,从前往后遍历每一个字符。每遍历一个字符,则将字符与后边的所有字符依次比较,判断是否含有相同字符。这
一种方法的时间复杂度为 O(n^2)。
(2)第二种思路是,首先对字符串进行一次遍历,将字符和字符出现的次数以键值对的形式存储在 Map 结构中。然后第二次遍历时
,去 Map 中获取对应字符出现的次数,找到第一个只出现一次的字符。这一种方法的时间复杂度为 O(n)。
35. 数组中的逆序对
============
题目:
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对
的总数 P。
思路:
(1)第一种思路是直接求解的方式,顺序扫描整个数组。每扫描到一个数字的时候,逐个比较该数字和它后面的数字的大小。如果
后面的数字比它小,则这两个数字就组成了一个逆序对。假设数组中含有 n 个数字。由于每个数字都要和 O(n)个数字作比
较,因此这个算法的时间复杂度是 O(n^2)。
(2)第二种方式是使用归并排序的方式,通过利用归并排序分解后进行合并排序时,来进行逆序对的统计,这一种方法的时间复杂
度为 O(nlogn)。
详细资料可以参考:
《数组中的逆序对》
36. 两个链表的第一个公共结点
=================
题目:
输入两个链表,找出它们的第一个公共结点。
思路:
(1)第一种方法是在第一个链表上顺序遍历每个结点,每遍历到一个结点的时候,在第二个链表上顺序遍历每个结点。如果在第二
个链表上有一个结点和第一个链表上的结点一样,说明两个链表在这个结点上重合,于是就找到了它们的公共结点。如果第一
个链表的长度为 m,第二个链表的长度为 n。这一种方法的时间复杂度是 O(mn)。
(2)第二种方式是利用栈的方式,通过观察我们可以发现两个链表的公共节点,都位于链表的尾部,以此我们可以分别使用两个栈
,依次将链表元素入栈。然后在两个栈同时将元素出栈,比较出栈的节点,最后一个相同的节点就是我们要找的公共节点。这
一种方法的时间复杂度为 O(m+n),空间复杂度为 O(m+n)。
(3)第三种方式是,首先分别遍历两个链表