最近求职中接到的好多外包公司的电话,一般我都是拒绝的,其中告知外包到微软的就有三家,有一家说是微软小冰项目,给了我八道算法题,都不是太难,有的在LeetCode上还做过,在这里记录一下,正好也整理下LeetCode上刷过的题。
这里记录的算法是只用python实现,也是我目前能想到的最优解,一共八个问题。
- 完成一个函数:def Add(num1, num2):其中,两个输入都是数字,都是字符串(如:“12345678986543210123456789”),要求计算两个数字的和,返回一个字符串,不能使用内置函数,如int,long等。例如,输入两个数字是:“1000000000000000”和“-1”,返回“999999999999999”。
这个问题比较简单了,主要就是三个小问题:
- 字符串和数字的互转
- 加法的进位
- 减法的借位
字符串和数字的互转不让用int函数,这个简单,python只要写个字典就解决了,C的话就要写switch case来一个一个比较了。这里就解决了字符转数字的问题了。
到的数字开始计算,因为要设计借位和进位,答案会有四种情况
- 正数 + 正数 = 正数 2 + 3 = 5
- 负数 + 负数 = 负数 -2 + -3 = -5
- 大正数 + 负数 = 正数 -2 + 3 = 1
- 正数 + 大负数 = 负数 2 + -3 = -1
貌似就是这样,但是观察结果除了负号就是两种,所以程序一开始应该先分析负号,进位的情况有1,2,借位情况是3,4,正好这两个结果除了负号答案一样,所以分两类就OK
1 | # 问题 1 |
- 给定一个数组nums,然后对其排序,使得排序结果满足nums[0] < nums[1] > nums[2] < nums[3]…。 例如给定数组nums=[1,2,3,4,5,6,7,8,9],其中一个满足条件的结果是1<6>2<7>3<8>4<9>5.给出一个结果即可(可能无解)。最优解法是O(n)时间复杂度和O(1)空间复杂度。9>8>7>6>
原题位置:https://leetcode.com/problems/wiggle-sort-ii/
这道题就比较有趣了,LeetCode上大神给出的算法挺多,但是最优解不是O(n),用python实现的话还能比O(n)小。
先说我看到题第一眼的想法和看了LeetCode上大神的方法吧,很简单就三行
1 | nums.sort() |
首先排序,找到中位数,然后把中位数左右两边的交叉相排就OK了。
好吧,详细一点吧,S代表比中位数小的,L代表比中位数大的,M代表中位数
1 | Small half: M . S . S . S Small half: M . S . S . S . |
根据这个原理还可以写成其他形式1
2
3nums.sort()
median = len(nums[::2])
nums[1::2], nums[::2] = nums[median:],nums[:median]
这个方式简单但是不满足O(n)时间复杂度的要求,这个方法是LeetCode上大神想出的叫virtual indexing,地址1
2
3
4
5
6
解释一下site()函数的作用
为了防止median的元素挨在一起,也就是说奇数位置上的值是median,同时与他相邻的某个偶数位置上的值也是median导致排序失败
为了避免这个问题,可以采用一种方法,即另j 每次移动两步,也就是说先另j直线奇数位置,再另j指向偶数位置,所以对于大小为10的序列,j的变化可能像是这样
1 -> 3 -> 5 -> 7 -> 9 -> 0 -> 2 -> 4 -> 6 -> 81
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暂且先不考虑怎么实现这样的改变,先说一下这样做带来的好处
由上面j的变化可知,j的改变是每次移动两步,所以,根据算法描述。所有和median相等的元素一定是最后才固定位置,又因为当j指向的值等于median时,是不与i和k指向的任何一个元素交换的。所以,每次移动两步带来的结果是这些median永远不可能相邻。换句话说就是永远不会出现两个median挨着的情况
```python
def question2_sort2(nums):
def site(n):
return (1 + 2 * n) % (len(nums) | 1)
nums.sort()
if len(nums) % 2 == 0:
median = (nums[len(nums) // 2] + nums[len(nums) // 2 - 1]) / 2
else:
median = nums[len(nums) // 2]
i, j, k = 0, 0, len(nums) - 1
while j <= k:
if nums[site(j)] > median:
nums[site(i)], nums[site(j)] = nums[site(j)], nums[site(i)]
i += 1
j += 1
elif nums[site(j)] < median:
nums[site(j)], nums[site(k)] = nums[site(k)], nums[site(j)]
k -= 1
j += 1 # 没错就是这里,我认为执行过交换后j就在正确的位置上了,所以我让j+1结果就是循环次数减少了,如果进行j+1则会循环N次,两种的结果不同但都复合条件
else:
j += 1
return nums
- 写一个函数,输入是两个int数组A和B。要求从A和B中分别取出一个数,使他们的和为20。打印出所有的组合。要求数字在数组中的位置和数字本身。比如输入为 A = [18, 2, 7, 8, 3], B = [17, 1, 19],输出为 3 (A4) + 17 (B0) = 20,表示A的第4个元素是3,B的第0个元素是17
这就是道送分题了,嵌套循环就OK了,没什么好说的。1
2
3
4
5
6
7def question3_take(a, b):
for i in range(len(a)):
for j in range(len(b)):
if a[i] + b[j] == 20:
print("%d (A%d) + %d (B%d) = 20" % (a[i], i, b[j], j))
return
print(" No solution!")
- 写一个函数,输入一个随机的01序列,打印出这个序列中最长的01交替出现的序列的起始位置和结束位置。例如:输入“000101010101101”,输出起始位置2, 结束位置10
这题让我纠结了下,因为需要记录的位置有点多
因为我们要遍历这个序列中所有的01所以要两个指针同时移动才能确保01的出现,当出现01我们计数器n +1,然后判断是否到结尾或者下一个不是01的情况,我们就结束这段,记录这段的长度和结束开始的位置,如果下一段出现的01长我们就替换掉上次的记录。
值得注意的是01可能出现在序列的奇数或偶数位上,所以要遍历两次,再比较奇偶上哪个长,返回长的那段。
1 | def func(i, j, num): |