第46题 全排列(重点)
给定一个没有重复数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
java解法:
public class Permutations46 {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> result= new ArrayList<>();
ArrayList<Integer> list = new ArrayList<>();
for(int i:nums){
list.add(i);
}
int first = 0;
backtrap(list,first,result);
return result;
}
public void backtrap(ArrayList<Integer> list,int first, List<List<Integer>> result){
if(first==list.size()){
result.add(new ArrayList(list));
}
for(int i = first;i<list.size();i++){
Collections.swap(list,first,i);
backtrap(list,first+1,result);
Collections.swap(list,first,i);
}
}
}
这道题是比较典型的关于回溯的题。在这道题中,我们以first来进行深度扩展。使用数字之间的交换来实现效果。以i来进行横向扩展。这种题型一点要背下来。
第60题 第k个排列(重)
给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
“123”
“132”
“213”
“231”
“312”
“321”
给定 n 和 k,返回第 k 个排列。
说明:
给定 n 的范围是 [1, 9]。
给定 k 的范围是[1, n!]。
示例 1:
输入: n = 3, k = 3
输出: "213"
示例 2:
输入: n = 4, k = 9
输出: "2314"
java代码:
import java.util.ArrayList;
import java.util.List;
public class Solution {
public String getPermutation(int n, int k) {
int[] nums = new int[n];
boolean[] used = new boolean[n];
for (int i = 0; i < n; i++) {
nums[i] = i + 1;
used[i] = false;
}
List<String> pre = new ArrayList<>();
return dfs(nums, used, n, k, 0, pre);
}
private int factorial(int n) {
// 这种编码方式包括了 0 的阶乘是 1 这种情况
int res = 1;
while (n > 0) {
res *= n;
n -= 1;
}
return res;
}
private String dfs(int[] nums, boolean[] used, int n, int k, int depth, List<String> pre) {
if (depth == n) {
StringBuilder sb = new StringBuilder();
for (String c : pre) {
sb.append(c);
}
return sb.toString();
}
int ps = factorial(n - 1 - depth);
for (int i = 0; i < n; i++) {
if (used[i]) {
continue;
}
if (ps < k) {
k -= ps;
continue;
}
pre.add(nums[i] + "");
used[i] = true;
return dfs(nums, used, n, k, depth + 1, pre);
}
// 如果参数正确的话,代码不会走到这里
throw new RuntimeException("参数错误");
}
}
这道题是利用了回溯和剪枝的方法。因为我们每次要找第k个节点。那么我们每次用回溯算法访问一个节点的时候。若那个 节点不是叶子节点。那么这个节点上能产生多少个组合是可以算出来的。如果算出来的结果小于k值那么这个节点就可以不用往下访问了。从而转移到另外的节点上面去。这道题有点难。
第61题 旋转列表
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
示例 2:
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL
java代码:
public class Rotate_List61 {
public ListNode rotateRight(ListNode head, int k) {
if(head==null) return head;
ListNode p1 = head;
ListNode p2 = head;
int length=0;
while(p1!=null){
length++;
p1=p1.next;
}
p1 = head;
k = k%length;
for(int i=0;i<k;i++){
p2= p2.next;
if(p2==null) p2=head;
}
if(p1==p2) return head;
while(p2.next!=null){
p1 = p1.next;
p2 = p2.next;
}
ListNode result = p1.next;
p2.next = head;
p1.next = null;
return result;
}
}
这道题比较简单,但是要注意一开始要先确定链表的length。不然直接用k来循环的话时间复杂度就是O(max(n,k))。而且在题内的时间消耗很大。
第62题 不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
问总共有多少条不同的路径?
java代码:
class Solution {
public int uniquePaths(int m, int n) {
int[][] f = new int[m+1][n+1];
for(int i=0;i<=m;i++){
f[m][0] = 0;
}
for(int i = 0;i<=n;i++){
f[0][n] = 0;
}
for(int i = 1;i<=m;i++){
for(int j = 1;j<=n;j++){
if(i==j&&j==1){
f[i][j] = 1;
continue;
}
f[i][j] = f[i-1][j]+f[i][j-1];
}
}
return f[m][n];
}
}
简单的动态规划超过了100的人
第63题 不同路径2
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
示例 1:
输入:
[
[0,0,0],
[0,1,0],
[0,0,0]
]
输出: 2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右
java代码:
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int[][] f = new int[m+1][n+1];
for(int i=0;i<=m;i++){
f[m][0] = 0;
}
for(int i = 0;i<=n;i++){
f[0][n] = 0;
}
for(int i = 1;i<=m;i++){
for(int j = 1;j<=n;j++){
if(obstacleGrid[m-i][n-j]==1){
f[i][j]=0;
continue;
}
if(i==j&&j==1){
f[i][j] = 1;
continue;
}
f[i][j] = f[i-1][j]+f[i][j-1];
}
}
return f[m][n];
}
}
和上一题基本一样。加了个判断和坐标映射而已。坐标映射是将f的坐标转换到障碍的坐标当中。
第64题最小路径和
用动态规划很简单。不说了
第69题 x的平方根
很简单注意进制的变化:
class Solution {
public int mySqrt(int x) {
if(x==0)return x;
float low = 1; float high = x;
while((int)low<(int)high){
double midle = ((double)low+(double)high)/2;
if(midle*midle==x){
return (int)midle;
}
else if(midle*midle>x)
high = (float) midle;
else
low = (float)midle;
}
if((int)low * (int)low > x){
return (int)(low)-1;}
else if((low+1)*(low+1)<(float)x)
return (int)(low+1);
else return (int)low;
}
}
使用了二分法