题目都来源于leetcode网站。题目的图片参考原网站绘制。
第一周:
62. Unique Paths
A robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).
How many possible unique paths are there?
Example 1:
Input: m = 3, n = 7 Output: 28 Example 2: Input: m = 3, n = 2 Output:
3 Explanation: From the top-left corner, there are a total of 3 ways
to reach the bottom-right corner:
- Right -> Down -> Down
- Down -> Down -> Right
- Down -> Right -> Down
Example 3
Input: m = 7, n = 3 Output: 28
Example 4:
Input: m = 3, n =3 Output: 6
这是关于机器人寻找路径的题,机器人从开始位置走到终点,输入为m,n。表示m,n的地图表格,机器人初始位置是(0,0),终点是右下角(m-1,n-1)。机器人每一步只能向下和向右走,输出走到终点的不重复的路径条数。
不管哪条路径,从起点到终点需要:向下(m-1 步)+向右(n-1步)。求解过程自然就和组合联系到一起,返回结果即为:
C
m
+
n
−
2
m
−
1
或
C
m
+
n
−
2
n
−
1
C_{m+n-2}^{m-1} 或 C_{m+n-2}^{n-1}
Cm+n−2m−1或Cm+n−2n−1
我直接编写了一个求解组合的函数:
public class Solution {
public int UniquePaths(int m, int n) {
return (int)CombinationResult(m+n-2,m-1);
}
public static Int64 CombinationResult(int m, int n)
{
Int64 result = 1;
if (m == 0 || n == 0) return result;
if (n > m / 2)
{
n = m - n;
}
for (int i = 0; i < n; i++)
{
result = result * (m - i) / (i + 1);
}
return result;
}
}
A robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).
Now consider if some obstacles are added to the grids. How many unique paths would there be?
An obstacle and space is marked as 1 and 0 respectively in the grid.
Example 1:
Input: obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
Output: 2
Explanation: There is one obstacle in the middle of the 3x3 grid above.
There are two ways to reach the bottom-right corner:
- Right -> Right -> Down -> Down
- Down -> Down -> Right -> Right Example 2: Input: obstacleGrid = [[0,1],[0,0]] Output: 1 Constraints: m == obstacleGrid.length n ==
obstacleGrid[i].length 1 <= m, n <= 100 obstacleGrid[i][j] is 0 or 1.
在Unique Paths的基础上增加了障碍,地图上有些块标记为不能通过。输入为二维数组,表示地图上每一点是否可以通过,0表示可以通过,1表示障碍不能通过。
直接通过列举的方法,找到所有的路径,提交结果发现计算超时。
查看了网站的解决方法以后,写下的代码如下:
public class Solution {
public int UniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.Length;
int n = obstacleGrid[0].Length;
int[,] array_temp = new int[m,n];
if ((m == 0 && n == 0) || obstacleGrid[0][0] == 1) return 0;
array_temp[0, 0] = 1;
for (int j = 0; j < n; j++)
{
if (obstacleGrid[0][j] == 1) break;
array_temp[0, j] = 1;
}
for (int i = 0; i < m; i++)
{
if (obstacleGrid[i][0] == 1) break;
array_temp[i, 0] = 1;
}
for (int i = 1; i < m; i++)
{
for (int j = 1; j < n; j++)
{
if (obstacleGrid[i][j] == 1)
{
array_temp[i, j] = 0;
}
else
{
array_temp[i, j] = array_temp[i-1, j]+ array_temp[i, j-1];
}
}
}
return array_temp[m-1,n-1];
}
}
具体的思路网站上解释的很清楚,我就简单描述下。
- 创建路径条数数组[m,n],表示能到该点的路径条数。
- 从起点[0,0]开始,起点如果没有障碍,则标记为1。如果起点有障碍,直接结束,返回0。
- 接着初始化第一行和第一列,没有遇到障碍就标记为1,一旦遇到障碍就将该位置和剩下的位置标记为0。
- 遍历剩下的位置,如果有障碍,直接赋值0,如果没有障碍,取值为上面和左面位置取值和 [m,n] = [m-1,n] + [m,n-1]。
- 最后返回 [m-1,n-1]位置的值即可。
参考网站的简单示意图:
第二周
78. Subsets
Given an integer array nums of unique elements, return all possible subsets (the power set).
The solution set must not contain duplicate subsets. Return the solution in any order.
Example 1:
Input: nums = [1,2,3]
Output: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
Example 2:
Input: nums = [0]
Output: [[],[0]]
Constraints:
1 <= nums.length <= 10
-10 <= nums[i] <= 10
All the numbers of nums are unique.
输入为整型数组,数组中的元素不重复,返回以数组中元素为集合的不重复的子集。具体可以参考题目中的例子。
这又是和组合相关的题目。先解决一个组合的问题:
给一个整型数组[1,2,3,4,5,6],输出元素数量为3的所有子集合。其实就是从5个元素中取出3个元素,所有不重复情况的组合。
public class Solution
{
public static List<IList<int>> GetCombination(int[] source, int n)
{
List<IList<int>> result = new List<IList<int>>();
if (source.Length < n)
{
return null;
}
else if (source.Length == n)
{
result.Add(source.ToList());
return result;
}
int[] index = new int[n];
List<IList<int>> list = new List<IList<int>>();
GetCombination(ref list, source, 0,source.Length-n, index, 1);
return list;
}
private static void GetCombination(ref List<IList<int>> list, int[] source,int from,int to, int[] index,int level)
{
for (int i = from; i <= to; i++)
{
//如果数组中有重复的元素需要加这行代码
//加入这行代码的前提是source是有序数组
//if (i > from && source[i] == source[i - 1]) continue;
index[level - 1] = i;
if (level == index.Length)
{
List<int> temp = new List<int>();
for (int j = 0; j < index.Length; j++)
{
temp.Add(source[index[j]]);
}
list.Add(temp);
}
else
{
GetCombination(ref list, source, i + 1, to + 1, index, level + 1);
}
}
}
}
Solution.GetCombination(new int[5] { 1, 2, 3, 4, 5 }, 3);
基本思路如下图:
解这题的代码:
public class Solution {
public static List<IList<int>> GetCombination(int[] source, int n)
{
List<IList<int>> result = new List<IList<int>>();
if (source.Length < n)
{
return null;
}
else if (source.Length == n)
{
result.Add(source.ToList());
return result;
}
int[] index = new int[n];
List<IList<int>> list = new List<IList<int>>();
GetCombination(ref list, source, 0,source.Length-n, index, 1);
return list;
}
private static void GetCombination(ref List<IList<int>> list, int[] source,int from,int to, int[] index,int level)
{
for (int i = from; i <= to; i++)
{
index[level - 1] = i;
if (level == index.Length)
{
List<int> temp = new List<int>();
for (int j = 0; j < index.Length; j++)
{
temp.Add(source[index[j]]);
}
list.Add(temp);
}
else
{
GetCombination(ref list, source, i + 1, to + 1, index, level + 1);
}
}
}
public IList<IList<int>> Subsets(int[] nums) {
List<IList<int>> result = new List<IList<int>>();
result.Add(new List<int>());
if (nums.Length == 0) return result;
for (int i = 1; i <= nums.Length; i++)
{
result = result.Concat(GetCombination(nums, i)).ToList<IList<int>>();
}
return result;
}
}
90. Subsets II
Given an integer array nums that may contain duplicates, return all possible subsets (the power set).
The solution set must not contain duplicate subsets. Return the solution in any order.
Example 1:
Input: nums = [1,2,2]
Output: [[],[1],[1,2],[1,2,2],[2],[2,2]]
Example 2:
Input: nums = [0]
Output: [[],[0]]
这一题是Subsets的升级版,输入的数组中有重复的元素,和上一题相比。先进行排序,然后再通过组合的函数计算结果。
public class Solution {
public IList<IList<int>> SubsetsWithDup(int[] nums) {
List<IList<int>> result = new List<IList<int>>();
result.Add(new List<int>());
if (nums.Length == 0) return result;
//先排序,然后再计算
for (int i = 0; i < nums.Length-1; i++)
{
for (int j = i+1; j < nums.Length; j++)
{
if (nums[i] > nums[j])
{
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
for (int i = 1; i <= nums.Length; i++)
{
result = result.Concat(GetCombination(nums, i)).ToList<IList<int>>();
}
return result;
}
public static List<IList<int>> GetCombination(int[] source, int n)
{
List<IList<int>> result = new List<IList<int>>();
if (source.Length < n)
{
return null;
}
else if (source.Length == n)
{
result.Add(source.ToList());
return result;
}
int[] index = new int[n];
List<IList<int>> list = new List<IList<int>>();
GetCombination(ref list, source, 0,source.Length-n, index, 1);
return list;
}
private static void GetCombination(ref List<IList<int>> list, int[] source,int from,int to, int[] index,int level)
{
for (int i = from; i <= to; i++)
{
if (i > from && source[i] == source[i - 1]) continue;
index[level - 1] = i;
if (level == index.Length)
{
List<int> temp = new List<int>();
for (int j = 0; j < index.Length; j++)
{
temp.Add(source[index[j]]);
}
list.Add(temp);
}
else
{
GetCombination(ref list, source, i + 1, to + 1, index, level + 1);
}
}
}
}
因为集合中有重复的元素,函数 private static void GetCombination(ref List<IList> list, int[] source,int from,int to, int[] index,int level) 中和上一题代码不一样的地方是:if (i > from && source[i] == source[i - 1]) continue;