个人在秋招和春招的时候刷了一些题目,主要是来自leetcode,通过学习别人的题解和个人的尝试,整理了一些题目较优的解法,现在分享给大家,可能对你的思维方式会有一丢丢的启发
数组
1. 两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
你可以按任意顺序返回答案。
示例 1:
输入:
nums= [2,7,11,15], target = 9
输出:[0,1]
解释:因为nums[0] +nums[1] == 9 ,返回 [0, 1] 。
解题思路
这道题最优的做法时间复杂度是 O(n)。
顺序扫描数组,对每一个元素,在 map 中找能组合给定值的另一半数字,如果找到了,直接返回 2 个数字的下标即可。如果找不到,就把这个数字存入 map 中,等待扫到“另一半”数字的时候,再取出来返回结果。
class Solution{
public int[] twoSum(int[] nums, int target){
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < nums.length; i++){
int another = target - nums[i];
if(map.containsKey(another)){
return new int[]{map.get(another), i};
}
map.put(nums[i], i);
}
return new int[]{-1, -1};
}
}
func twoSum(nums []int, target int) []int {
m := make(map[int]int, 0)
for i, v := range(nums){
another := target - v
if j, ok := m[another]; ok{
return []int{j, i}
}
m[v] = i
}
return []int{-1, -1}
}
2. 寻找两个正序数组的中位数
给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。
进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?
示例 1:
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
示例 3:
输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
示例 4:
输入:nums1 = [], nums2 = [1]
输出:1.00000
示例 5:
输入:nums1 = [2], nums2 = []
输出:2.00000
提示:
- nums1.length == m
- nums2.length == n
- 0 <= m <= 1000
- 0 <= n <= 1000
- 1 <= m + n <= 2000
- -106 <= nums1[i], nums2[i] <= 106
解题思路
给出两个有序数组,要求找出这两个数组合并以后的有序数组中的中位数。要求时间复杂度为 O(log (m+n))。
这一题最容易想到的办法是把两个数组合并,然后取出中位数。但是合并有序数组的操作是 O(max(n,m)) 的,不符合题意。看到题目给的 log 的时间复杂度,很容易联想到二分搜索。
由于要找到最终合并以后数组的中位数,两个数组的总大小也知道,所以中间这个位置也是知道的。只需要二分搜索一个数组中切分的位置,另一个数组中切分的位置也能得到。为了使得时间复杂度最小,所以二分搜索两个数组中长度较小的那个数组。
关键的问题是如何切分数组 1 和数组 2 。其实就是如何切分数组 1 。先随便二分产生一个 midA,切分的线何时算满足了中位数的条件呢?即,线左边的数都小于右边的数,即,nums1[midA-1] ≤ nums2[midB] && nums2[midB-1] ≤ nums1[midA] 。如果这些条件都不满足,切分线就需要调整。如果 nums1[midA] < nums2[midB-1],说明 midA 这条线划分出来左边的数小了,切分线应该右移;如果 nums1[midA-1] > nums2[midB],说明 midA 这条线划分出来左边的数大了,切分线应该左移。经过多次调整以后,切分线总能找到满足条件的解。
假设现在找到了切分的两条线了,数组 1 在切分线两边的下标分别是 midA - 1 和 midA。数组 2 在切分线两边的下标分别是 midB - 1 和 midB。最终合并成最终数组,如果数组长度是奇数,那么中位数就是 max(nums1[midA-1], nums2[midB-1])。如果数组长度是偶数,那么中间位置的两个数依次是:max(nums1[midA-1], nums2[midB-1]) 和 min(nums1[midA], nums2[midB]),那么中位数就是 (max(nums1[midA-1], nums2[midB-1]) + min(nums1[midA], nums2[midB])) / 2。
class Solution{
public double findMedianSortedArrays(int[] nums1, int[] nums2){
if(nums1.length > nums2.length){
return findMedianSortedArrays(nums2, nums1);
}
int low = 0, high = nums1.length;
int k = (nums1.length + nums2.length + 1) >> 1;
int midA = 0, midB = 0;
while(low <= high){
midA = (low + high) >> 1;
midB = k - midA;
if(midA > 0 && nums1[midA - 1] > nums2[midB]){
high = midA - 1;
} else if(midA < nums1.length && nums1[midA] < nums2[midB - 1]){
low = midA + 1;
} else{
break;
}
}
int midLeft = 0, midRight = 0;
if(midA == 0){
midLeft = nums2[midB - 1];
} else if(midB == 0){
midLeft = nums1[midA - 1];
} else{
midLeft = Math.max(nums1[midA - 1], nums2[midB - 1]);
}
if(((nums1.length + nums2.length) & 1) == 1){
return (double) midLeft;
}
if(midA == nums1.length){
midRight = nums2[midB];
} else if(midB == nums2.length){
midRight = nums1[midA];
} else{
midRight = Math.min(nums1[midA], nums2[midB]);
}
return (double) (midLeft + midRight) / 2.0;
}
}
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
if len(nums1) > len(nums2){
return findMedianSortedArrays(nums2, nums1);
}
low, high, k, midA, midB := 0, len(nums1), (len(nums1) + len(nums2) + 1) >> 1, 0, 0
for low <= high{
midA = (low + high) >> 1
midB = k - midA
if midA > 0 && nums1[midA - 1] > nums2[midB]{
high = midA - 1
} else if midA < len(nums1) && nums1[midA] < nums2[midB - 1]{
low = midA + 1
} else{
break
}
}
midLeft, midRight := 0, 0
if midA == 0{
midLeft = nums2[midB - 1]
} else if midB == 0{
midLeft = nums1[midA - 1]
} else{
midLeft = max(nums1[midA - 1], nums2[midB - 1])
}
if (len(nums1) + len(nums2)) & 1 == 1{
return float64(midLeft)
}
if midA == len(nums1){
midRight = nums2[midB]
} else if midB == len(nums2){
midRight = nums1[midA]
} else{
midRight = min(nums1[midA], nums2[midB])
}
return float64(midLeft + midRight) / 2
}
func max(a, b int) int{
if a > b{
return a
}
return b
}
func min(a, b int) int{
if a < b{
return a
}
return b
}
3.盛最多水的容器
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器。
示例 1:
输入:[1,8,6,2,5,4,8,3,7]
输出:49解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:
输入:height = [1,1]
输出:1
示例 3:
输入:height = [4,3,2,1,4]
输出:16
示例 4:
输入:height = [1,2,1]
输出:2
提示:
n = height.length
2 <= n <= 3 * 104
0 <= height[i] <= 3 * 104
class Solution{
public int maxArea(int[] height){
int res = 0, start = 0, end = height.length - 1;
while(start < end){
int width = end - start;
int high = 0;
if(height[start] < height[end]){
high = height[start++];
} else{
high = height[end--];
}
int area = high * width;
res = Math.max(area, res);
}
return res;
}
}
func maxArea(height []int) int{
res, start, end := 0, 0, len(height) - 1
for start < end{
width := end - start
high := 0
if height[start] < height[end]{
high = height[start]
start++
} else{
high = height[end]
end--
}
area := high * width
if area > res{
res = area
}
}
return res
}
4. 存在重复元素
给定一个整数数组,判断是否存在重复元素。
如果存在一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。
示例 1:
输入: [1,2,3,1]
输出: true
示例 2:
输入: [1,2,3,4]
输出: false
示例 3:
输入: [1,1,1,3,3,4,3,2,4,2]
输出: true
class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet<>(nums.length);
for(int n : nums){
if(set.contains(n)){
return true;
}
set.add(n);
}
return false;
}
}
func containsDuplicate(nums []int) bool {
m := make(map[int]bool, len(nums))
for _, v := range(nums){
if _, contain := m[v]; contain{
return true
}
m[v] = true
}
return false
}
5. 反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入:[“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]
示例 2:
输入:[“H”,“a”,“n”,“n”,“a”,“h”]
输出:[“h”,“a”,“n”,“n”,“a”,“H”]
class Solution {
public void reverseString(char[] s) {
int mid = s.length / 2;
for(int i = 0; i < mid; i++) {
char c = s[i];
s[i] = s[s.length - 1 - i];
s[s.length - 1 - i] = c;
}
}
}
func reverseString(s []byte) {
mid := len(s) / 2
for i := 0; i < mid; i++ {
c := s[i]
s[i] = s[len(s) - 1 - i]
s[len(s) - 1 - i] = c
}
}
6. 合并两个有序数组
给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。你可以假设 nums1 的空间大小等于 m + n,这样它就有足够的空间保存来自 nums2 的元素。
示例 1:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
示例 2:
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
提示:
-
nums1.length == m + n
-
nums2.length == n
-
0 <= m, n <= 200
-
1 <= m + n <= 200
-
-109 <= nums1[i], nums2[i] <= 109
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int i = m - 1, j = n - 1;
for(int k = m + n - 1; k >= 0; k--) {
int n1 = Integer.MIN_VALUE, n2 = Integer.MIN_VALUE;
if(i >= 0) {
n1 = nums1[i];
}
if(j >= 0) {
n2 = nums2[j];
}
nums1[k] = n1 > n2 ? nums1[i--] : nums2[j--];
}
}
}
func merge(nums1 []int, m int, nums2 []int, n int) {
i, j, min := m-1, n-1, - 1 << 32
for k := m+n-1; k >= 0; k-- {
n1, n2 := min, min
if i >= 0 {
n1 = nums1[i]
}
if j >= 0 {
n2 = nums2[j]
}
if n1 > n2 {
nums1[k] = n1
i--
} else {
nums1[k] = n2
j--
}
}
}
7. 非递减数列
难度简单456
给你一个长度为 n 的整数数组,请你判断在 最多 改变 1 个元素的情况下,该数组能否变成一个非递减数列。
我们是这样定义一个非递减数列的: 对于数组中所有的 i (0 <= i <= n-2),总满足 nums[i] <= nums[i + 1]。
示例 1:
输入: nums = [4,2,3]
输出: true
解释: 你可以通过把第一个4变成1来使得它成为一个非递减数列。
示例 2:
输入: nums = [4,2,1]
输出: false
解释: 你不能在只改变一个元素的情况下将其变为非递减数列。
说明:
1 <= n <= 10 ^ 4- 10 ^ 5 <= nums[i] <= 10 ^ 5
class Solution {
public boolean checkPossibility(int[] nums) {
int cnt = 0;
for(int i = 0; i < nums.length - 1; i++) {
int x = nums[i], y = nums[i+1];
if(x > y) {
if(++cnt > 1) {
return false;
}
if(i > 0 && nums[i-1] > y) {
nums[i+1] = x;
}
}
}
return true;
}
}
func checkPossibility(nums []int) {
cnt := 0
for i := 0; i < len(nums) - 1; i++ {
x, y := nums[i], nums[i+1]
if x > y {
cnt++
if cnt > 1 {
return false
}
if i > 0 && nums[i-1] > y {
nums[i+1] = x
}
}
}
return true
}
8. 跳跃游戏 VI *
给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。
一开始你在下标 0 处。每一步,你最多可以往前跳 k 步,但你不能跳出数组的边界。也就是说,你可以从下标 i 跳到 [i + 1, min(n - 1, i + k)] 包含 两个端点的任意位置。
你的目标是到达数组最后一个位置(下标为 n - 1 ),你的 得分 为经过的所有数字之和。
请你返回你能得到的 最大得分 。
示例 1:
输入:nums = [1,-1,-2,4,-7,3], k = 2
输出:7
解释:你可以选择子序列 [1,-1,4,3] (上面加粗的数字),和为 7 。
示例 2:
输入:nums = [10,-5,-2,4,0,3], k = 3
输出:17
解释:你可以选择子序列 [10,4,3] (上面加粗数字),和为 17 。
示例 3:
输入:nums = [1,-5,-20,4,-1,3,-6,-3], k = 2
输出:0
提示:
- 1 <= nums.length, k <= 105
- -104 <= nums[i] <= 104
class Solution {
public int maxResult(int[] nums, int k) {
int n = nums.length;
int[] dp = new int[n];
Deque<Integer> queue = new LinkedList<>();
dp[0] = nums[0];
queue.offerLast(0);
for(int i = 1; i < n; i++) {
if(i > k && i - k - 1 == queue.getFirst()) {
queue.pollFirst();
}
dp[i] = nums[i] + dp[queue.getFirst()];
while(!queue.isEmpty() && dp[queue.getLast()] < dp[i]) {
queue.pollLast();
}
queue.offerLast(i);
}
return dp[n - 1];
}
}
func maxResult(nums []int, k int) int {
n := len(nums)
dp := make([]int, n)
queue := make([]int, 0)
dp[0] = nums[0]
queue = append(queue, 0)
for i := 1; i < n; i++ {
if i > k && i - k - 1 == queue[0] {
queue = queue[1:]
}
dp[i] = nums[i] + dp[queue[0]]
for len(queue) > 0 && dp[queue[len(queue) - 1]] < dp[i] {
queue = queue[:len(queue) - 1]
}
queue = append(queue, i)
}
return dp[n - 1]
}
9. 移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:
必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。
class Solution {
public void moveZeroes(int[] nums) {
int j = 0;
for(int i = 0; i < nums.length; i++) {
if(nums[i] != 0) {
if(i != j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
j++;
}
}
}
}
func moveZeroes(nums []int) {
j := 0
for i := range nums {
if nums[i] != 0 {
if i != j {
nums[i], nums[j] = nums[j], nums[i]
}
j++
}
}
}
10. 找到所有数组中消失的数字
难度简单600
给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。
找到所有在 [1, n] 范围之间没有出现在数组中的数字。
您能在不使用额外空间且时间复杂度为*O(n)*的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。
示例:
输入:
[4,3,2,7,8,2,3,1]
输出:
[5,6]
class Solution {
public List<Integer> findDisappearedNumbers(int[] nums) {
int n = nums.length;
for(int i = 0; i < n; i++) {
int x = (nums[i] - 1) % n;
nums[x] += n;
}
List<Integer> res = new ArrayList<>();
for(int i = 0; i < n; i++) {
if(nums[i] <= n) {
res.add(i+1);
}
}
return res;
}
}
func findDisappearedNumbers(nums []int) []int {
n := len(nums)
for _, v := range nums {
x := (v - 1) % n
nums[x] += n
}
res := make([]int, 0)
for i := 0; i < n; i++ {
if nums[i] <= n {
res = append(res, i+1)
}
}
return res
}
11. 螺旋矩阵
给你一个 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]
提示:
-
m == matrix.length
-
n == matrix[i].length
-
1 <= m, n <= 10
-
-100 <= matrix[i][j] <= 100
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> res = new ArrayList<>();
int row = matrix.length;
if(row == 0) {
return res;
}
int col = matrix[0].length;
int lr = 1, ud = 1, r = 0, c = 0;
while(row > 0 && col > 0) {
row--;
for(int i = 0; i < col; i++) {
res.add(matrix[r][c]);
c += lr;
}
c -= lr;
r += ud;
lr *= -1;
col--;
for(int i = 0; i < row; i++) {
res.add(matrix[r][c]);
r += ud;
}
r -= ud;
c += lr;
ud *= -1;
}
return res;
}
}
func spiralOrder(matrix [][]int) []int {
res := make([]int, 0)
row := len(matrix)
if row == 0 {
return res
}
col := len(matrix[0])
lr, ud, r, c := 1, 1, 0, 0
for row > 0 && col > 0 {
row--
for i := 0; i < col; i++ {
res = append(res, matrix[r][c])
c += lr
}
c -= lr
r += ud
lr *= -1
col--
for i := 0; i < row; i++ {
res = append(res, matrix[r][c])
r += ud
}
r -= ud
c += lr
ud *= -1
}
return res
}
12. 螺旋矩阵 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
class Solution {
public int[][] generateMatrix(int n) {
int[][] res = new int[n][n];
int row = n, col = n, r = 0, c = 0;
int lr = 1, ud = 1, element = 1;
while(row > 0 && col > 0) {
row--;
for(int i = 0; i < col; i++) {
res[r][c] = element++;
c += lr;
}
c -= lr;
r += ud;
lr *= -1;
col--;
for(int i = 0; i < row; i++) {
res[r][c] = element++;
r += ud;
}
r -= ud;
c += lr;
ud *= -1;
}
return res;
}
}
func generateMatrix(n int) [][]int {
res := make([][]int, n)
for i := 0; i < n; i++ {
res[i] = make([]int, n)
}
row, col, r, c := n, n, 0, 0
lr, ud, element := 1, 1, 1
for row > 0 && col > 0 {
row--
for i := 0; i < col; i++ {
res[r][c] = element
element++
c += lr
}
c -= lr
r += ud
lr *= -1
col--
for i := 0; i < row; i++ {
res[r][c] = element
element++
r += ud
}
r -= ud
c += lr
ud *= -1
}
return res
}
13. 有效的数独
判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
上图是一个部分填充的有效的数独。
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
示例 1:
输入:
[
[“5”,“3”,".",".",“7”,".",".",".","."],
[“6”,".",".",“1”,“9”,“5”,".",".","."],
[".",“9”,“8”,".",".",".",".",“6”,"."],
[“8”,".",".",".",“6”,".",".",".",“3”],
[“4”,".",".",“8”,".",“3”,".",".",“1”],
[“7”,".",".",".",“2”,".",".",".",“6”],
[".",“6”,".",".",".",".",“2”,“8”,"."],
[".",".",".",“4”,“1”,“9”,".",".",“5”],
[".",".",".",".",“8”,".",".",“7”,“9”]
]
输出: true
示例 2:
输入:
[
[“8”,“3”,".",".",“7”,".",".",".","."],
[“6”,".",".",“1”,“9”,“5”,".",".","."],
[".",“9”,“8”,".",".",".",".",“6”,"."],
[“8”,".",".",".",“6”,".",".",".",“3”],
[“4”,".",".",“8”,".",“3”,".",".",“1”],
[“7”,".",".",".",“2”,".",".",".",“6”],
[".",“6”,".",".",".",".",“2”,“8”,"."],
[".",".",".",“4”,“1”,“9”,".",".",“5”],
[".",".",".",".",“8”,".",".",“7”,“9”]
]
输出: false
解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。
但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。
说明:
-
一个有效的数独(部分已被填充)不一定是可解的。
-
只需要根据以上规则,验证已经填入的数字是否有效即可。
-
给定数独序列只包含数字 1-9 和字符 ‘.’ 。
-
给定数独永远是 9x9 形式的。
class Solution {
public boolean isValidSudoku(char[][] board) {
boolean[][] row = new boolean[9][9];
boolean[][] col = new boolean[9][9];
boolean[][] box = new boolean[9][9];
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
if(board[i][j] == '.') {
continue;
}
int pos = board[i][j] - '1';
if(row[i][pos]) return false;
if(col[pos][j]) return false;
if(box[j / 3 + i / 3 * 3][pos]) return false;
row[i][pos] = true;
col[pos][j] = true;
box[j / 3 + i / 3 * 3][pos] = true;
}
}
return true;
}
}
func isValidSudoku(board [][]byte) bool {
row := make([][]bool, 9)
col := make([][]bool, 9)
box := make([][]bool, 9)
for i := 0; i < 9; i++ {
row[i] = make([]bool, 9)
col[i] = make([]bool, 9)
box[i] = make([]bool, 9)
}
for i := 0; i < 9; i++ {
for j := 0; j < 9; j++ {
if board[i][j] == '.' {
continue
}
pos := board[i][j] - '1'
if row[i][pos] || col[pos][j] || box[j / 3 + i / 3 * 3][pos] {
return false
}
row[i][pos] = true
col[pos][j] = true
box[j / 3 + i / 3 * 3][pos] = true
}
}
return true
}
14. 除自身以外数组的乘积
给你一个长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。
示例:
输入: [1,2,3,4]
输出: [24,12,8,6]
提示:题目数据保证数组之中任意元素的全部前缀元素和后缀(甚至是整个数组)的乘积都在 32 位整数范围内。
说明: 请不要使用除法,且在 O(n) 时间复杂度内完成此题。
进阶:
你可以在常数空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)
class Solution {
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] res = new int[n];
res[0] = 1;
for(int i = 1; i < n; i++) {
res[i] = res[i-1] * nums[i-1];
}
int R = 1;
for(int i = n-1; i >= 0; i--) {
res[i] *= R;
R *= nums[i];
}
return res;
}
}
func productExceptSelf(nums []int) []int {
n := len(nums)
res := make([]int, n)
res[0] = 1
for i := 1; i < n; i++ {
res[i] = res[i-1] * nums[i-1]
}
R := 1
for i := n-1; i >= 0; i-- {
res[i] *= R
R *= nums[i]
}
return res
}
15. 数组的度
难度简单249
给定一个非空且只包含非负数的整数数组 nums,数组的度的定义是指数组里任一元素出现频数的最大值。
你的任务是在 nums 中找到与 nums 拥有相同大小的度的最短连续子数组,返回其长度。
示例 1:
输入:[1, 2, 2, 3, 1]
输出:2
解释:
输入数组的度是2,因为元素1和2的出现频数最大,均为2.
连续子数组里面拥有相同度的有如下所示:
[1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2]
最短连续子数组[2, 2]的长度为2,所以返回2.
示例 2:
输入:[1,2,2,3,1,4,2]
输出:6
提示:
nums.length在1到 50,000 区间范围内。nums[i]是一个在 0 到 49,999 范围内的整数。
class Solution {
public int findShortestSubArray(int[] nums) {
int maxCount = 0, minWindow = 0;
Map<Integer, int[]> map = new HashMap<>();
for(int i = 0; i < nums.length; i++) {
int[] pair = map.get(nums[i]);
if(pair == null) {
pair = new int[]{i, 1};
map.put(nums[i], pair);
} else {
pair[1]++;
}
if(pair[1] > maxCount) {
maxCount = pair[1];
minWindow = i - pair[0] + 1;
} else if(pair[1] == maxCount) {
minWindow = Math.min(minWindow, i - pair[0] + 1);
}
}
return minWindow;
}
}
func findShortestSubArray(nums []int) int {
maxCount, minWindow, len := 0, 0, len(nums)
m := make(map[int][]int, 0)
for i := 0; i < len; i++ {
pair, ok := m[nums[i]]
if !ok {
pair = make([]int, 2)
pair[0] = i
pair[1] = 1
} else {
pair[1]++
}
m[nums[i]] = pair
if pair[1] > maxCount {
maxCount = pair[1]
minWindow = i - pair[0] + 1
} else if pair[1] == maxCount {
minWindow = min(minWindow, i - pair[0] + 1)
}
}
return minWindow
}
func min(n1, n2 int) int {
if n1 < n2 {
return n1
}
return n2
}
16. 最接近的三数之和
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
示例:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
提示:
-
3 <= nums.length <= 10^3
-
-10^3 <= nums[i] <= 10^3
-
-10^4 <= target <= 10^4
class Solution {
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int res = 0, diff = Integer.MAX_VALUE;
for(int i = 0; i < nums.length - 2; i++) {
for(int j = i+1, k = nums.length - 1; j < k;) {
int sum = nums[i] + nums[j] + nums[k];
if(Math.abs(sum - target) < diff) {
res = sum;
diff = Math.abs(sum - target);
}
if(sum == target) {
return sum;
} else if(sum < target) {
j++;
} else {
k--;
}
}
}
return res;
}
}
func threeSumClosest(nums []int, target int) int {
res, diff, n := 0, 1 << 32 - 1, len(nums)
sort.Ints(nums)
for i := 0; i < n-2; i++ {
for j, k := i+1, n-1; j < k; {
sum := nums[i] + nums[j] + nums[k]
if abs(sum - target) < diff {
res, diff = sum, abs(sum - target)
}
if sum == target {
return sum
} else if sum < target {
j++
} else {
k--
}
}
}
return res
}
func abs(n int) int {
if n < 0 {
return -n
}
return n
}
17. 旋转图像
给定一个 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]]
示例 3:
输入:matrix = [[1]]
输出:[[1]]
示例 4:
输入:matrix = [[1,2],[3,4]]
输出:[[3,1],[4,2]]
提示:
-
matrix.length == n
-
matrix[i].length == n
-
1 <= n <= 20
-
-1000 <= matrix[i][j] <= 1000
class Solution {
public void rotate(int[][] matrix) {
int n = matrix.length, mid = n >> 1;
for(int i = 0; i < mid; i++) {
for(int j = 0; j < n; j++) {
swap(matrix, i, j, n-1-i, j);
}
}
for(int i = 0; i < n; i++) {
for(int j = i+1; j < n; j++) {
swap(matrix, i, j, j, i);
}
}
}
private void swap(int[][] matrix, int i1, int j1, int i2, int j2) {
int temp = matrix[i1][j1];
matrix[i1][j1] = matrix[i2][j2];
matrix[i2][j2] = temp;
}
}
func rotate(matrix [][]int) {
n := len(matrix)
mid := n >> 1
for i := 0; i < mid; i++ {
ni := n - 1 - i
for j := 0; j < n; j++ {
matrix[i][j], matrix[ni][j] = matrix[ni][j], matrix[i][j]
}
}
for i := 0; i < n; i++ {
for j := i+1; j < n; j++ {
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
}
}
}

51万+

被折叠的 条评论
为什么被折叠?



