59. 螺旋矩阵 II,60. 排列序列,61. 旋转链表,每题做详细思路梳理,配套Python&Java双语代码, 2024.03.21 可通过leetcode所有测试用例。
目录
59. 螺旋矩阵 II
解题思路
完整代码
Java
Python
60. 排列序列
解题思路
完整代码
Java
Python
61. 旋转链表
解题思路
解题思路:
完整代码
Java
Python
59. 螺旋矩阵 II
给你一个正整数
n
,生成一个包含1
到n2
所有元素,且元素按顺时针顺序螺旋排列的n x n
正方形矩阵matrix
。示例 1:
输入:n = 3 输出:[[1,2,3],[8,9,4],[7,6,5]]示例 2:
输入:n = 1 输出:[[1]]提示:
1 <= n <= 20
解题思路
完整代码
Java
public class Solution {
public int[][] generateMatrix(int n) {
int[][] matrix = new int[n][n];
int num = 1;
int top = 0, bottom = n - 1, left = 0, right = n - 1;
while (left <= right && top <= bottom) {
for (int i = left; i <= right; i++) {
matrix[top][i] = num++;
}
top++;
for (int i = top; i <= bottom; i++) {
matrix[i][right] = num++;
}
right--;
for (int i = right; i >= left; i--) {
matrix[bottom][i] = num++;
}
bottom--;
for (int i = bottom; i >= top; i--) {
matrix[i][left] = num++;
}
left++;
}
return matrix;
}
}
Python
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
if n == 1:
return [[1]]
matrix = [[0] * n for _ in range(n)]
num, top, bottom, left, right = 1, 0, n - 1, 0, n - 1
while left <= right and top <= bottom:
for i in range(left, right + 1):
matrix[top][i] = num
num += 1
top += 1
for i in range(top, bottom + 1):
matrix[i][right] = num
num += 1
right -= 1
for i in range(right, left - 1, -1):
matrix[bottom][i] = num
num += 1
bottom -= 1
for i in range(bottom, top - 1, -1):
matrix[i][left] = num
num += 1
left += 1
return matrix
60. 排列序列
给出集合
[1,2,3,...,n]
,其所有元素共有n!
种排列。按大小顺序列出所有排列情况,并一一标记,当
n = 3
时, 所有排列如下:
"123"
"132"
"213"
"231"
"312"
"321"
给定
n
和k
,返回第k
个排列。示例 1:
输入:n = 3, k = 3 输出:"213"示例 2:
输入:n = 4, k = 9 输出:"2314"示例 3:
输入:n = 3, k = 1 输出:"123"
解题思路
-
初始化:创建一个列表
numbers
存储从 1 到 n 的所有数字,用于构造排列。同时,计算(n-1)!
(记为factorial
),因为在固定第一个数字的情况下,后面的数字可以形成(n-1)!
种排列。 -
调整 k:由于列表的索引从 0 开始,但排列是从 1 开始计数的,所以先将 k 减去 1,以便与索引对齐。
-
构造排列:遍历从 0 到 n-1 的每个位置,对于每个位置:
- 确定该位置上的数字应该是
numbers
中的哪一个。这可以通过将 k 除以当前的factorial
值得到。这会给出当前位置应该使用numbers
中的哪个数字。 - 更新 k 为 k 除以
factorial
的余数,为下一个位置的计算做准备。 - 更新
factorial
为factorial
除以当前的剩余数字的数量,因为每确定一个数字后,剩余可选数字就减少一个。 - 从
numbers
中移除已经使用过的数字,确保不会重复使用。
- 确定该位置上的数字应该是
-
返回结果:将步骤 3 中确定的数字连接起来,形成字符串作为最终答案。
完整代码
Java
public class Solution {
public String getPermutation(int n, int k) {
List<Integer> numbers = new ArrayList<>();
int factorial = 1;
for (int i = 1; i <= n; i++) {
numbers.add(i);
factorial *= i;
}
k--; // 将 k 转换为基于 0 的索引
StringBuilder answer = new StringBuilder();
for (int i = 0; i < n; i++) {
factorial /= (n - i);
int index = k / factorial;
k %= factorial;
answer.append(numbers.get(index));
numbers.remove(index);
}
return answer.toString();
}
}
Python
class Solution:
def getPermutation(self, n: int, k: int) -> str:
numbers = list(range(1, n+1))
factorial = 1
for i in range(1, n):
factorial *= i
k -= 1 # 将 k 转换为基于 0 的索引
answer = []
for i in range(n-1, -1, -1):
index = k // factorial
k %= factorial
if i != 0:
factorial //= i
answer.append(str(numbers[index]))
numbers.pop(index)
return ''.join(answer)
61. 旋转链表
给你一个链表的头节点
head
,旋转链表,将链表每个节点向右移动k
个位置。示例 1:
输入:head = [1,2,3,4,5], k = 2 输出:[4,5,1,2,3]示例 2:
输入:head = [0,1,2], k = 4 输出:[2,0,1]提示:
- 链表中节点的数目在范围
[0, 500]
内-100 <= Node.val <= 100
解题思路
旋转链表意味着将链表的后部分移动到链表的前部分。为了实现这一点,我们可以遵循以下步骤:
解题思路:
-
链表长度和尾节点:首先遍历链表以确定链表的长度
n
,并在此过程中获得链表的尾节点。这一步骤有助于我们理解需要移动多少个节点以及如何连接链表的尾部到头部。 -
计算实际移动次数:由于链表的长度是固定的,如果移动次数
k
大于链表长度n
,那么移动k
次实际上等同于移动k % n
次(因为每移动n
次,链表就会恢复到原始状态)。因此,我们只需要移动k % n
次。 -
找到新的头节点:新的头节点将是从链表尾部数起的第
k % n
个节点的下一个节点。因此,我们需要从头节点开始,移动(n - k % n - 1)
次来找到新的尾节点。 -
执行旋转:将当前的尾节点(新的尾节点)的
next
指针指向原来的头节点,将原来的尾节点的next
指针指向null
,并更新头节点为新的头节点。
完整代码
Java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
public class Solution {
public ListNode rotateRight(ListNode head, int k) {
if (head == null || head.next == null || k == 0) return head;
// 计算链表长度并获取尾节点
int length = 1;
ListNode tail = head;
while (tail.next != null) {
tail = tail.next;
length++;
}
// 计算需要移动的实际次数
k = k % length;
if (k == 0) return head;
// 找到新的尾节点
ListNode newTail = head;
for (int i = 0; i < length - k - 1; i++) {
newTail = newTail.next;
}
// 执行旋转
ListNode newHead = newTail.next;
newTail.next = null;
tail.next = head;
return newHead;
}
}
Python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def rotateRight(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
if not head or not head.next or k == 0:
return head
# 计算链表长度并获取尾节点
length, tail = 1, head
while tail.next:
tail = tail.next
length += 1
# 计算需要移动的实际次数
k = k % length
if k == 0:
return head
# 找到新的尾节点
new_tail = head
for _ in range(length - k - 1):
new_tail = new_tail.next
# 执行旋转
new_head = new_tail.next
new_tail.next = None
tail.next = head
return new_head