CS-Notes/notes/面试总结.md
孙海洲 b3e1afed81
Update 面试总结.md
添加小米校招2018笔试题第一题
2018-09-20 21:05:06 +08:00

186 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- GFM-TOC -->
* [1. 字符串组合](#1-字符串组合)
* [2. 整数组合求和](#2-整数组合求和)
* [3. 数组中重复的数字](#3-数组中重复的数字)
* [参考文献](#参考文献)
<!-- GFM-TOC -->
# 1. 字符串组合
## 题目描述
给定三种类型的小球P、Q、R每种小球的数量分别为np、nq、nr个。现在想讲这些小球排成一条直线但是不允许相同类型的小球相邻问有多少种排序方法。
如若np=2nq=1,nr=1则共有6种排列方式PQRP、QPRP、PRQP、PRPQ、RPQP以及PQPR。如果无法组合出合适的结果则输出0.
### 输入
```code
一行以空格相隔的三个数分别表示为np、nq、nr。
```
### 输出
```code
排列方法的数量。
```
### 样例输入
```code
2 1 1
```
### 样例输出
```code
6
```
## 解题思路
本题采用一种比较直接的方式进行解题,分为如下步骤:
1. 求解给定P、Q、R个数的时候的全排列提供`Python`提供的`itertools.permutations`来实现,此时肯定有很多重复。
2. 去掉重复的情况,通过`Python`提供的`set`来实现。
3. 通过遍历找出相邻元素重复的串。
4. 求两个集合的差集,即为答案。
```python
import itertools
np, nq, nr = [int(k) for k in raw_input().split(" ")]
count = 0
result = []
for i in itertools.permutations("P"*np + "Q"*nq + "R"*nr,np + nq + nr):
result.append(''.join(i))
result_same = []
for element in list(set(result)):
for j in range(1, len(element)):
if element[j-1] == element[j]:
result_same.append(element)
ret_list = list(set(result)^set(result_same))
print len(ret_list)
```
# 2. 整数组合求和
## 题目描述
小米之家是成人糖果店。里面有很多便宜,好用,好玩的产品。中秋节到了,小米之家想给米粉准备一些固定金额大礼包。对于给定的一个金额,需要判断能不能用
不同种产品(一种产品在礼包最多出现一次)组合出来这个金额。聪明的你来帮帮米家的小伙伴吧。
### 输入
```code
输入NN是正整数 N < = 200
输入N个价格p正整数 p <= 10000用单空格分割
输入金额MM是正整数M <= 100000
```
### 输出
```code
能组合出来输出1
否则输出0
```
### 样例输入
```code
6
99 199 1999 10000 39 1499
10238
```
### 样例输出
```code
1
```
## 解题思路
本题采用一种比较直接的方式进行解题,分为如下步骤:
1. 对输入np进行排序方便后面快速结束。
2. 求解给定np时候的0~n个组合的和提供`Python`提供的`itertools.permutations`来实现。
3. 如果较小的数相加已经大于目标,可以提前跳出本次循环。
```python
import itertools
n = int(raw_input())
np = [int(k) for k in raw_input().split(" ")]
np.sort()
sum_np = int(raw_input())
flag = 0
for i in range(n):
for j in itertools.permutations(np, i):
if sum(j) > sum_np:
continue;
if sum(j) == sum_np:
flag = 1;
break;
print flag
```
# 3. 数组中重复的数字
[NowCoder](https://www.nowcoder.com/practice/623a5ac0ea5b4e5f95552655361ae0a8?tpId=13&tqId=11203&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
## 题目描述
在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复几次。请找出数组中任意一个重复的数字。例如,如果输入长度为 7 的数组 {2, 3, 1, 0, 2, 5},那么对应的输出是第一个重复的数字 2。
要求复杂度为 O(N) + O(1),也就是时间复杂度 O(N),空间复杂度 O(1)。因此不能使用排序的方法,也不能使用额外的标记数组。牛客网讨论区这一题的首票答案使用 nums[i] + length 来将元素标记,这么做会有加法溢出问题。
## 解题思路
这种数组元素在 [0, n-1] 范围内的问题,可以将值为 i 的元素放到第 i 个位置上。
以 (2, 3, 1, 0, 2, 5) 为例:
```text-html-basic
position-0 : (2,3,1,0,2,5) // 2 <-> 1
(1,3,2,0,2,5) // 1 <-> 3
(3,1,2,0,2,5) // 3 <-> 0
(0,1,2,3,2,5) // already in position
position-1 : (0,1,2,3,2,5) // already in position
position-2 : (0,1,2,3,2,5) // already in position
position-3 : (0,1,2,3,2,5) // already in position
position-4 : (0,1,2,3,2,5) // nums[i] == nums[nums[i]], exit
```
遍历到位置 4 时,该位置上的数为 2但是第 2 个位置上已经有一个 2 的值了,因此可以知道 2 重复。
```java
public boolean duplicate(int[] nums, int length, int[] duplication) {
if (nums == null || length <= 0)
return false;
for (int i = 0; i < length; i++) {
while (nums[i] != i) {
if (nums[i] == nums[nums[i]]) {
duplication[0] = nums[i];
return true;
}
swap(nums, i, nums[i]);
}
}
return false;
}
private void swap(int[] nums, int i, int j) {
int t = nums[i]; nums[i] = nums[j]; nums[j] = t;
}
```
# 参考文献
- 何海涛. 剑指 Offer[M]. 电子工业出版社, 2012.