2018-09-19 10:01:05 +08:00
|
|
|
|
<!-- GFM-TOC -->
|
|
|
|
|
* [1. 字符串组合](#1-字符串组合)
|
2018-09-24 21:11:45 +08:00
|
|
|
|
* [2. 整数组合求和](#2-整数组合求和)
|
2018-09-19 10:01:05 +08:00
|
|
|
|
* [3. 数组中重复的数字](#3-数组中重复的数字)
|
2018-09-25 13:22:05 +08:00
|
|
|
|
* [4. 二维数组中的查找](#4-二维数组中的查找)
|
|
|
|
|
* [5. 替换空格](#5-替换空格)
|
2018-09-25 18:55:15 +08:00
|
|
|
|
* [6. 从尾到头打印链表](#6-从尾到头打印链表)
|
2018-09-19 10:01:05 +08:00
|
|
|
|
|
|
|
|
|
* [参考文献](#参考文献)
|
|
|
|
|
<!-- GFM-TOC -->
|
|
|
|
|
|
|
|
|
|
# 1. 字符串组合
|
|
|
|
|
|
|
|
|
|
## 题目描述
|
|
|
|
|
|
|
|
|
|
给定三种类型的小球P、Q、R,每种小球的数量分别为np、nq、nr个。现在想讲这些小球排成一条直线,但是不允许相同类型的小球相邻,问有多少种排序方法。
|
|
|
|
|
如若np=2,nq=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)
|
|
|
|
|
```
|
|
|
|
|
|
2018-09-24 21:11:45 +08:00
|
|
|
|
# 2. 整数组合求和
|
2018-09-19 10:01:05 +08:00
|
|
|
|
|
2018-09-24 21:11:45 +08:00
|
|
|
|
## 题目描述
|
|
|
|
|
|
|
|
|
|
小米之家是成人糖果店。里面有很多便宜,好用,好玩的产品。中秋节到了,小米之家想给米粉准备一些固定金额大礼包。对于给定的一个金额,需要判断能不能用
|
|
|
|
|
不同种产品(一种产品在礼包最多出现一次)组合出来这个金额。聪明的你来帮帮米家的小伙伴吧。
|
|
|
|
|
|
|
|
|
|
### 输入
|
|
|
|
|
```code
|
|
|
|
|
输入N(N是正整数, N < = 200)
|
|
|
|
|
输入N个价格p(正整数, p <= 10000)用单空格分割
|
|
|
|
|
输入金额M(M是正整数,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
|
|
|
|
|
```
|
2018-09-19 10:01:05 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 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;
|
|
|
|
|
}
|
|
|
|
|
```
|
2018-09-25 13:22:05 +08:00
|
|
|
|
|
2018-09-24 21:11:45 +08:00
|
|
|
|
```python
|
|
|
|
|
nums = [int(k) for k in raw_input().split(" ")]
|
|
|
|
|
print nums
|
|
|
|
|
|
|
|
|
|
def duplicate(nums):
|
|
|
|
|
if len(nums) <= 0:
|
|
|
|
|
return -1, False
|
|
|
|
|
for i in range(len(nums)):
|
|
|
|
|
while nums[i] != i:
|
|
|
|
|
if nums[i] == nums[nums[i]]:
|
|
|
|
|
return nums[i], True
|
|
|
|
|
t = nums[i]
|
|
|
|
|
nums[i] = nums[nums[i]]
|
|
|
|
|
nums[nums[i]] = t
|
|
|
|
|
# nums[i], nums[nums[i]] = nums[nums[i]], nums[i]
|
|
|
|
|
return -1, False
|
|
|
|
|
|
|
|
|
|
print duplicate(nums)
|
|
|
|
|
```
|
2018-09-19 10:01:05 +08:00
|
|
|
|
|
2018-09-25 13:22:05 +08:00
|
|
|
|
# 4. 二维数组中的查找
|
|
|
|
|
|
|
|
|
|
[NowCoder](https://www.nowcoder.com/practice/abc3fe2ce8e146608e868a70efebf62e?tpId=13&tqId=11154&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
|
|
|
|
|
|
|
|
|
|
## 题目描述
|
|
|
|
|
|
|
|
|
|
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
|
|
|
|
|
|
|
|
|
|
```html
|
|
|
|
|
Consider the following matrix:
|
|
|
|
|
[
|
|
|
|
|
[1, 4, 7, 11, 15],
|
|
|
|
|
[2, 5, 8, 12, 19],
|
|
|
|
|
[3, 6, 9, 16, 22],
|
|
|
|
|
[10, 13, 14, 17, 24],
|
|
|
|
|
[18, 21, 23, 26, 30]
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
Given target = 5, return true.
|
|
|
|
|
Given target = 20, return false.
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 解题思路
|
|
|
|
|
|
|
|
|
|
从右上角开始查找。矩阵中的一个数,它左边的数都比它小,下边的数都比它大。因此,从右上角开始查找,就可以根据 target 和当前元素的大小关系来缩小查找区间。
|
|
|
|
|
|
|
|
|
|
复杂度:O(M + N) + O(1)
|
|
|
|
|
|
|
|
|
|
当前元素的查找区间为左下角的所有元素,例如元素 12 的查找区间如下:
|
|
|
|
|
|
|
|
|
|
<div align="center"> <img src="../pics//f94389e9-55b1-4f49-9d37-00ed05900ae0.png" width="250"/> </div><br>
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
public boolean Find(int target, int[][] matrix) {
|
|
|
|
|
if (matrix == null || matrix.length == 0 || matrix[0].length == 0)
|
|
|
|
|
return false;
|
|
|
|
|
int rows = matrix.length, cols = matrix[0].length;
|
|
|
|
|
int r = 0, c = cols - 1; // 从右上角开始
|
|
|
|
|
while (r <= rows - 1 && c >= 0) {
|
|
|
|
|
if (target == matrix[r][c])
|
|
|
|
|
return true;
|
|
|
|
|
else if (target > matrix[r][c])
|
|
|
|
|
r++;
|
|
|
|
|
else
|
|
|
|
|
c--;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
target = int(input())
|
|
|
|
|
|
|
|
|
|
# nums = [[1, 4, 7, 11, 15], [2, 5, 8, 12, 19], [3, 6, 9, 16, 22], [10, 13, 14, 17, 24], [18, 21, 23, 26, 30]]
|
|
|
|
|
|
|
|
|
|
nums = eval(input())
|
|
|
|
|
|
|
|
|
|
def find(target, matrix):
|
|
|
|
|
if len(matrix) == 0 or len(matrix[0]) == 0:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
rows, cols = len(matrix), len(matrix[0])
|
|
|
|
|
r, c = 0, cols - 1
|
|
|
|
|
|
|
|
|
|
while r <= rows - 1 and c >= 0:
|
|
|
|
|
if target == matrix[r][c]:
|
|
|
|
|
return True
|
|
|
|
|
elif target > matrix[r][c]:
|
|
|
|
|
r += 1
|
|
|
|
|
else:
|
|
|
|
|
c -= 1
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
print (find(target, nums))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
# 5. 替换空格
|
|
|
|
|
|
|
|
|
|
[NowCoder](https://www.nowcoder.com/practice/4060ac7e3e404ad1a894ef3e17650423?tpId=13&tqId=11155&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
|
|
|
|
|
|
|
|
|
|
## 题目描述
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
将一个字符串中的空格替换成 "%20"。
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
Input:
|
|
|
|
|
"We Are Happy"
|
|
|
|
|
|
|
|
|
|
Output:
|
|
|
|
|
"We%20Are%20Happy"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 解题思路
|
|
|
|
|
|
|
|
|
|
在字符串尾部填充任意字符,使得字符串的长度等于替换之后的长度。因为一个空格要替换成三个字符(%20),因此当遍历到一个空格时,需要在尾部填充两个任意字符。
|
|
|
|
|
|
|
|
|
|
令 P1 指向字符串原来的末尾位置,P2 指向字符串现在的末尾位置。P1 和 P2从后向前遍历,当 P1 遍历到一个空格时,就需要令 P2 指向的位置依次填充 02%(注意是逆序的),否则就填充上 P1 指向字符的值。
|
|
|
|
|
|
|
|
|
|
从后向前遍是为了在改变 P2 所指向的内容时,不会影响到 P1 遍历原来字符串的内容。
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
public String replaceSpace(StringBuffer str) {
|
|
|
|
|
int P1 = str.length() - 1;
|
|
|
|
|
for (int i = 0; i < P1 + 1; i++)
|
|
|
|
|
if (str.charAt(i) == ' ')
|
|
|
|
|
str.append(" ");
|
|
|
|
|
|
|
|
|
|
int P2 = str.length() - 1;
|
|
|
|
|
while (P1 >= 0 && P2 > P1) {
|
|
|
|
|
char c = str.charAt(P1--);
|
|
|
|
|
if (c == ' ') {
|
|
|
|
|
str.setCharAt(P2--, '0');
|
|
|
|
|
str.setCharAt(P2--, '2');
|
|
|
|
|
str.setCharAt(P2--, '%');
|
|
|
|
|
} else {
|
|
|
|
|
str.setCharAt(P2--, c);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return str.toString();
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```python
|
2018-09-25 17:28:14 +08:00
|
|
|
|
target = input()
|
2018-09-25 13:22:05 +08:00
|
|
|
|
|
2018-09-25 17:28:14 +08:00
|
|
|
|
print (target.replace(" ", "%20"))
|
2018-09-25 13:22:05 +08:00
|
|
|
|
```
|
2018-09-19 10:01:05 +08:00
|
|
|
|
|
2018-09-25 17:28:14 +08:00
|
|
|
|
|
2018-09-25 18:55:15 +08:00
|
|
|
|
# 6. 从尾到头打印链表
|
|
|
|
|
|
|
|
|
|
[NowCoder](https://www.nowcoder.com/practice/d0267f7f55b3412ba93bd35cfa8e8035?tpId=13&tqId=11156&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
|
|
|
|
|
|
|
|
|
|
## 题目描述
|
|
|
|
|
|
|
|
|
|
输入链表的第一个节点,从尾到头反过来打印出每个结点的值。
|
|
|
|
|
|
|
|
|
|
<div align="center"> <img src="../pics//d99dc9e2-197c-4085-813d-7195da1c6762.png" width="300"/> </div><br>
|
|
|
|
|
|
|
|
|
|
## 解题思路
|
|
|
|
|
|
|
|
|
|
### 使用栈
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
|
|
|
|
|
Stack<Integer> stack = new Stack<>();
|
|
|
|
|
while (listNode != null) {
|
|
|
|
|
stack.add(listNode.val);
|
|
|
|
|
listNode = listNode.next;
|
|
|
|
|
}
|
|
|
|
|
ArrayList<Integer> ret = new ArrayList<>();
|
|
|
|
|
while (!stack.isEmpty())
|
|
|
|
|
ret.add(stack.pop());
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 使用递归
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
|
|
|
|
|
ArrayList<Integer> ret = new ArrayList<>();
|
|
|
|
|
if (listNode != null) {
|
|
|
|
|
ret.addAll(printListFromTailToHead(listNode.next));
|
|
|
|
|
ret.add(listNode.val);
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 使用头插法
|
|
|
|
|
|
|
|
|
|
利用链表头插法为逆序的特点。
|
|
|
|
|
|
|
|
|
|
头结点和第一个节点的区别:
|
|
|
|
|
|
|
|
|
|
- 头结点是在头插法中使用的一个额外节点,这个节点不存储值;
|
|
|
|
|
- 第一个节点就是链表的第一个真正存储值的节点。
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
|
|
|
|
|
// 头插法构建逆序链表
|
|
|
|
|
ListNode head = new ListNode(-1);
|
|
|
|
|
while (listNode != null) {
|
|
|
|
|
ListNode memo = listNode.next;
|
|
|
|
|
listNode.next = head.next;
|
|
|
|
|
head.next = listNode;
|
|
|
|
|
listNode = memo;
|
|
|
|
|
}
|
|
|
|
|
// 构建 ArrayList
|
|
|
|
|
ArrayList<Integer> ret = new ArrayList<>();
|
|
|
|
|
head = head.next;
|
|
|
|
|
while (head != null) {
|
|
|
|
|
ret.add(head.val);
|
|
|
|
|
head = head.next;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```python
|
2018-09-25 18:59:00 +08:00
|
|
|
|
def printListFromTailToHead(listNode):
|
2018-09-25 18:55:15 +08:00
|
|
|
|
# write code here
|
|
|
|
|
l = list()
|
|
|
|
|
while listNode:
|
|
|
|
|
l.append(listNode.val)
|
|
|
|
|
listNode = listNode.next
|
|
|
|
|
l.reverse()
|
|
|
|
|
return l
|
|
|
|
|
```
|
2018-09-25 17:28:14 +08:00
|
|
|
|
|
2018-09-19 10:01:05 +08:00
|
|
|
|
# 参考文献
|
|
|
|
|
|
|
|
|
|
- 何海涛. 剑指 Offer[M]. 电子工业出版社, 2012.
|