LeetCode热题100(四)
189. 轮转数组
题目详情
https://leetcode.cn/problems/rotate-array/
给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。
示例 1:
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]
示例 2:
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释:
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]
解答过程
一开始是想交换数组元素值,但是思考半天没思考出来,后来发现其实clone新数组会很简单
java
public void rotate(int[] nums, int k) {
int[] clone = nums.clone();
for (int i = 0; i < nums.length; i++) {
int index = (i + k) % nums.length;
nums[index] = clone[i];
}
}
238. 除了自身以外数组的乘积
题目详情
https://leetcode.cn/problems/product-of-array-except-self/
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除了 nums[i] 之外其余各元素的乘积 。
题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。
请 **不要使用除法,**且在 O(n) 时间复杂度内完成此题。
示例 1:
输入: nums = [1,2,3,4]
输出: [24,12,8,6]
示例 2:
输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]
解答过程
看到题目的第一想法是算出总和,然后去算除自身以外的乘积,后来才注意到不允许除法,看了答案才豁然开朗
java
public int[] productExceptSelf(int[] nums) {
int[] left = new int[nums.length];
Arrays.fill(left, 1);
for (int i = 1; i < nums.length; i++) {
left[i] = nums[i - 1] * left[i - 1];
}
int[] right = new int[nums.length];
Arrays.fill(right, 1);
for (int i = nums.length - 2; i >= 0; i--) {
right[i] = nums[i + 1] * right[i + 1];
}
int[] answer = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
answer[i] = left[i] * right[i];
}
return answer;
}
73. 矩阵置零
题目详情
https://leetcode.cn/problems/set-matrix-zeroes/
给定一个 *m* x *n* 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法**。**
示例 1:

输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
输出:[[1,0,1],[0,0,0],[1,0,1]]
示例 2:

输入:matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]
输出:[[0,0,0,0],[0,4,5,0],[0,3,1,0]]
解答过程
第一想法是两次遍历 第一次记录所有含0的行号和列号 第二次根据记录修改值 但是再数据过多的时候超时
java
public void setZeroes(int[][] matrix) {
ArrayList<Integer> row = new ArrayList<>();
ArrayList<Integer> column = new ArrayList<>();
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (matrix[i][j] == 0) {
row.add(i);
column.add(j);
}
}
}
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (row.contains(i) || column.contains(j)) {
matrix[i][j] = 0;
}
}
}
}
看了官方题解发现确实应该将ArrayList换成boolean[]
- boolean[] row/col
是**数组索引访问**,时间复杂度O(1) - ArrayList.contains()
是**线性遍历查找**,时间复杂度O(k)
java
public void setZeroes(int[][] matrix) {
boolean[] row = new boolean[matrix.length];
boolean[] column = new boolean[matrix[0].length];
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (matrix[i][j] == 0) {
row[i] = true;
column[j] = true;
}
}
}
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (row[i] || column[j]) {
matrix[i][j] = 0;
}
}
}
}
54. 螺旋矩阵
题目详情
https://leetcode.cn/problems/spiral-matrix/
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
示例 1:

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
示例 2:

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
解答过程
自己没想出解题方式,看了官方解题思路,才解出来,核心思路是碰到越界或已访问的就转向
java
public List<Integer> spiralOrder(int[][] matrix) {
ArrayList<Integer> list = new ArrayList<>();
int rowSize = matrix.length;
int columnSize = matrix[0].length;
if (columnSize == 0) {
return list;
}
int total = rowSize * columnSize;
boolean[][] visited = new boolean[rowSize][columnSize];
int row = 0;
int column = 0;
// 右、下、左、上
int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
int direction = 0;
while (total > 0) {
System.out.println(matrix[row][column] + " " + Arrays.toString(directions[direction]));
list.add(matrix[row][column]);
visited[row][column] = true;
int nextRow = row + directions[direction][0];
int nextColumn = column + directions[direction][1];
if (nextColumn >= columnSize || nextColumn < 0 || nextRow >= rowSize || nextRow < 0 || visited[nextRow][nextColumn]) {
direction = (direction + 1) % directions.length;
}
row += directions[direction][0];
column += directions[direction][1];
total--;
}
return list;
}
48. 旋转图像
题目详情
https://leetcode.cn/problems/rotate-image/
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在**原地** 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
示例 1:

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]
示例 2:

输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]
解答过程
直接看图可能并不是很直观,看最后的输出结果更明显[i][j]会变更为[rowSize - 1 - j][i]处的数字
java
public void rotate(int[][] matrix) {
int rowSize = matrix.length;
int columnSize = matrix[0].length;
int[][] clone = new int[rowSize][columnSize];
for (int i = 0; i < rowSize; i++) {
clone[i] = matrix[i].clone();
}
for (int i = 0; i < rowSize; i++) {
for (int j = 0; j < columnSize; j++) {
matrix[i][j] = clone[rowSize - 1 - j][i];
}
}
}
240. 搜索二维矩阵 II
题目详情
https://leetcode.cn/problems/search-a-2d-matrix-ii/
编写一个高效的算法来搜索 *m* x *n* 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:
- 每行的元素从左到右升序排列。
- 每列的元素从上到下升序排列。
示例 1:

输入: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]], target = 5
输出:true
示例 2:

输入: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]], target = 20
输出:false
解答过程
再明知target不可能存在的时候要放弃循环
java
public boolean searchMatrix(int[][] matrix, int target) {
for (int i = 0; i < matrix.length; i++) {
if (matrix[i][0] > target) {
break;
}
for (int j = 0; j < matrix[i].length; j++) {
if (matrix[i][j] == target) {
return true;
}
if (matrix[i][j] > target) {
break;
}
}
}
return false;
}
142. 环形链表 II
题目详情
https://leetcode.cn/problems/linked-list-cycle-ii/
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始 )。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。
解答过程
利用hashset去判断节点是否遍及过
java
public ListNode detectCycle(ListNode head) {
HashSet<ListNode> nodes = new HashSet<>();
while (head != null) {
if (nodes.contains(head)) {
return head;
}
nodes.add(head);
head = head.next;
}
return head;
}
2. 两数相加
题目详情
https://leetcode.cn/problems/add-two-numbers/
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例 1:

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
示例 2:
输入:l1 = [0], l2 = [0]
输出:[0]
示例 3:
输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]
解题过程
不断便利链表,计算和,并记录是否超过10,逐个进行处理
java
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode ln = new ListNode(-1);
ListNode l = ln;
int decade = 0;
while (l1 != null || l2 != null || decade != 0) {
int sum = 0;
if (l1 != null) {
sum += l1.val;
l1 = l1.next;
}
if (l2 != null) {
sum += l2.val;
l2 = l2.next;
}
sum += decade;
if (sum >= 10) {
decade = 1;
sum %= 10;
} else {
decade = 0;
}
ln.next = new ListNode(sum);
ln = ln.next;
}
return l.next;
}
19. 删除链表的倒数第 N 个结点
题目详情
https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例 1:

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
示例 2:
输入:head = [1], n = 1
输出:[]
示例 3:
输入:head = [1,2], n = 1
输出:[1]
解答过程
第一思路是遍历一遍记录节点,执行移除操作,随后重新拼接链表
java
public ListNode removeNthFromEnd(ListNode head, int n) {
ArrayList<ListNode> nodes = new ArrayList<>();
while (head != null) {
nodes.add(head);
head = head.next;
}
nodes.remove(nodes.size() - n);
ListNode ns = new ListNode(-1);
ListNode ln = ns;
for (ListNode node : nodes) {
ns.next = node;
ns = ns.next;
ns.next = null;
}
return ln.next;
}
24. 两两交换链表中的节点
题目详情
https://leetcode.cn/problems/swap-nodes-in-pairs/
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例 1:

输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例 2:
输入:head = []
输出:[]
示例 3:
输入:head = [1]
输出:[1]
解答过程
java
public ListNode swapPairs(ListNode head) {
int c = 0;
ListNode node1 = null;
ListNode node2 = null;
ListNode ln = new ListNode(-1);
ListNode l = ln;
while (head != null) {
c++;
System.out.println(head.val + " " + c);
if (c % 2 == 1) {
node1 = head;
} else {
node2 = head;
}
if (c % 2 == 0) {
ListNode temp = node2.next;
ln.next = node2;
node2.next = node1;
node1.next = temp;
ln = ln.next.next;
head = node1;
node1 = null;
node2 = null;
}
head = head.next;
}
if (node1 != null) {
ln.next = node1;
}
return l.next;
}
看了官方的思路确实更好,递归
java
public ListNode swapPairs(ListNode head) {
System.out.println(head);
if (head == null || head.next == null) {
return head;
}
ListNode newHead = head.next;
head.next = swapPairs(newHead.next);
newHead.next = head;
return newHead;
}