LeetCodeCampsDay64额外题目
1365. 有多少小于当前数字的数字
https://leetcode.cn/problems/how-many-numbers-are-smaller-than-the-current-number/
给你一个数组 nums
,对于其中每个元素 nums[i]
,请你统计数组中比它小的所有数字的数目。
换而言之,对于每个 nums[i]
你必须计算出有效的 j
的数量,其中 j
满足 j != i
且 nums[j] < nums[i]
。
以数组形式返回答案。
示例 1:
1 | 输入:nums = [8,1,2,2,3] |
示例 2:
1 | 输入:nums = [6,5,4,8] |
示例 3:
1 | 输入:nums = [7,7,7,7] |
提示:
2 <= nums.length <= 500
0 <= nums[i] <= 100
代码
- 时间复杂度O(Nlogn)
- 空间复杂度O(N)
1 | class Solution: |
941. 有效的山脉数组
https://leetcode.cn/problems/valid-mountain-array/
给定一个整数数组 arr
,如果它是有效的山脉数组就返回 true
,否则返回 false
。
让我们回顾一下,如果 arr
满足下述条件,那么它是一个山脉数组:
arr.length >= 3
- 在
0 < i < arr.length - 1
条件下,存在i
使得:arr[0] < arr[1] < ... arr[i-1] < arr[i]
arr[i] > arr[i+1] > ... > arr[arr.length - 1]
示例 1:
1 | 输入:arr = [2,1] |
示例 2:
1 | 输入:arr = [3,5,5] |
示例 3:
1 | 输入:arr = [0,3,2,1] |
提示:
1 <= arr.length <= 104
0 <= arr[i] <= 104
思路一
本题目要经过再次循环判断,先判断是否单调递增;再判断是否单调递减;
先找到假设中的TheMaxIndex递增序列里的最大值,再进行单调递减的判断,最终根据TheMaxIndex是否非头非尾以及index是否遍历完来判断结果
代码一
- 时间复杂度O(N)
- 空间复杂度O(1)
1 | class Solution: |
思路二
使用二指针,left指针从左向右遍历,判断是否单调递增;right指针从右向左遍历,判断是否单调递减;
若最终两个指针位置相同,并且非头非尾(!=0且!=L-1),说明才符合要求
代码二
- 时间复杂度O(N)
- 空间复杂度O(1)
1 | class Solution: |
1207. 独一无二的出现次数
https://leetcode.cn/problems/unique-number-of-occurrences/
给你一个整数数组 arr
,如果每个数的出现次数都是独一无二的,就返回 true
;否则返回 false
。
示例 1:
1 | 输入:arr = [1,2,2,1,1,3] |
示例 2:
1 | 输入:arr = [1,2] |
示例 3:
1 | 输入:arr = [-3,0,1,-3,1,1,1,-3,10,0] |
提示:
1 <= arr.length <= 1000
-1000 <= arr[i] <= 1000
思路
回归本题,本题强调了-1000 <= arr[i] <= 1000,那么就可以用数组来做哈希,arr[i]作为哈希表(数组)的下标,那么arr[i]可以是负数,怎么办?负数不能做数组下标。
此时可以定义一个2001大小的数组,例如int count[2001];,统计的时候,将arr[i]统一加1000,这样就可以统计arr[i]的出现频率了。
题目中要求的是是否有相同的频率出现,那么需要再定义一个哈希表(数组)用来记录频率是否重复出现过,bool fre[1001]; 定义布尔类型的就可以了,因为题目中强调1 <= arr.length <= 1000,所以哈希表大小为1000就可以了。
如图所示:
代码
- 时间复杂度O(N)
- 空间复杂度O(N)
1 | class Solution: |
283. 移动零
https://leetcode.cn/problems/move-zeroes/
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
1 | 输入: nums = [0,1,0,3,12] |
示例 2:
1 | 输入: nums = [0] |
提示:
1 <= nums.length <= 104
-231 <= nums[i] <= 231 - 1
**进阶:**你能尽量减少完成的操作次数吗?
思路
使用双指针,slow指向可以放数据的下标,fast用来遍历,如果fast遇到非0则将nums[fast]赋值到nums[slow];最后将nums[slow:]这个范围内的值赋值为0
如动画所示:
代码
1 | class Solution: |
189. 轮转数组
https://leetcode.cn/problems/rotate-array/
给定一个整数数组 nums
,将数组中的元素向右轮转 k
个位置,其中 k
是非负数。
示例 1:
1 | 输入: nums = [1,2,3,4,5,6,7], k = 3 |
示例 2:
1 | 输入:nums = [-1,-100,3,99], k = 2 |
提示:
1 <= nums.length <= 105
-231 <= nums[i] <= 231 - 1
0 <= k <= 105
进阶:
- 尽可能想出更多的解决方案,至少有 三种 不同的方法可以解决这个问题。
- 你可以使用空间复杂度为
O(1)
的 原地 算法解决这个问题吗?
数据复制思路
我们遍历原数组,将原数组下标为 i 的元素放至新数组下标为 (i+k)modn 的位置,最后将新数组拷贝至原数组即可。
数据复制代码
- 时间复杂度O(N)
- 空间复杂度O(N)
1 | class Solution: |
数组翻转思路
该方法基于如下的事实:当我们将数组的元素向右移动 k 次后,尾部 k mod n 个元素会移动至数组头部,其余元素向后移动 k mod n 个位置。
该方法为数组的翻转:我们可以先将所有元素翻转,这样尾部的 k mod n 个元素就被移至数组头部,然后我们再翻转 [0,k mod n−1] 区间的元素和 [k mod n,n−1] 区间的元素即能得到最后的答案。
我们以 n=7,k=3 为例进行如下展示:
操作 | 结果 |
---|---|
原始数组 | 1 2 3 4 5 6 7 |
翻转所有元素 | 7 6 5 4 3 2 1 |
翻转 [0,k mod n−1] 区间的元素 | 5 6 7 4 3 2 1 |
翻转 [k mod n,n−1] 区间的元素 | 5 6 7 1 2 3 4 |
下面为了省事,直接将k = k % n
数组翻转代码
- 时间复杂度O(N)
- 空间复杂度O(1)
1 | class Solution: |
724. 寻找数组的中心下标
https://leetcode.cn/problems/find-pivot-index/
给你一个整数数组 nums
,请计算数组的 中心下标 。
数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
如果中心下标位于数组最左端,那么左侧数之和视为 0
,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。
如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1
。
示例 1:
1 | 输入:nums = [1, 7, 3, 6, 5, 6] |
示例 2:
1 | 输入:nums = [1, 2, 3] |
示例 3:
1 | 输入:nums = [2, 1, -1] |
提示:
1 <= nums.length <= 104
-1000 <= nums[i] <= 1000
思路一
使用两个数组分别从左向右、从右向左计算累加值
随后,对两个数组判断是否存在一个同一下标i的相同值
中心下标位置的数字不参加运算
双指针,left从左向右;right从右向左遍历;同时求和
0, 1, 8, 11, 17
, 22, 28
22, 21, 14, 17
, 11, 6, 0
如果遇到下标位置一致且两个数组值一致,则返回这个下标
0, 2
, 3, 2
2
, 0, -1, 0
代码一
1 | class Solution: |
思路二
先求出数组整体和,再从左向右遍历,实时地计算sumOfLeft以及sumOfRight的和,判断是否相等即可
代码二
- 时间复杂度O(N)
- 空间复杂度O(N)
1 | class Solution: |
34. 在排序数组中查找元素的第一个和最后一个位置
https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/
给你一个按照非递减顺序排列的整数数组 nums
,和一个目标值 target
。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target
,返回 [-1, -1]
。
你必须设计并实现时间复杂度为 O(log n)
的算法解决此问题。
示例 1:
1 | 输入:nums = [5,7,7,8,8,10], target = 8 |
示例 2:
1 | 输入:nums = [5,7,7,8,8,10], target = 6 |
示例 3:
1 | 输入:nums = [], target = 0 |
提示:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums
是一个非递减数组-109 <= target <= 109
思路
本题基本指定使用二分查找,基础的二分查找中,仅能查到指定的target,但本题目要求查这个target的区间范围。
所以,本题目需要划分成查找target的左、右区间边界(即,例如5,7,7,8,8,10,需要找到第一个10作为右边界,以及第二个7作为左边界),所以需要对原二分查找进行修改
原二分查找的代码如下
1 | L = len(nums) |
如果要查左边界leftBorder,应该当nums[mid] >= target时,将mid - 1赋值给leftBorder
比如,5,7,7,8,8,10,当left为3,right为5,mid为4,即nums[mid]为第二个8时,此时满足nums[mid]>=target,则leftBorder就是mid - 1 = 3
代码
- 时间复杂度O(logN)
- 空间复杂度O(N)
1 | class Solution: |