来源:力扣(LeetCode)
链接:https://leetcode.cn/leetbook/detail/top-interview-questions-easy/
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
26. 删除有序数组中的重复项
给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。
将最终结果插入 nums 的前 k 个位置后返回 k 。
不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
示例 1:
输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。
示例 2:
输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。
提示:
- 1 <= nums.length <= 3 * 104
- -104 <= nums[i] <= 104
- nums 已按 升序 排列
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
nums.erase(unique(nums.begin(),nums.end()), nums.end());
return nums.size();
}
};
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if(nums.empty()) return 0; // nums长度为0或1,不用处理直接返回
if(nums.size() == 1) return 1;
vector<int>::iterator slow = nums.begin(), fast = nums.begin()+1; // 双指针
while(fast != nums.end()){ // 快指针找不同的数,找到一个就存到慢指针哪里,直到快指针找完整个数组
if(*slow != *fast){
*(++slow) = *fast;
}
++fast;
}
if(slow != nums.end()-1) // 如果有重复的,就清除slow之后的
nums.erase(slow+1, nums.end());
return nums.size();
}
};
66. 加一
给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。
示例 1:
输入:digits = [1,2,3]
输出:[1,2,4]
解释:输入数组表示数字 123。
示例 2:
输入:digits = [4,3,2,1]
输出:[4,3,2,2]
解释:输入数组表示数字 4321。
示例 3:
输入:digits = [0]
输出:[1]
提示:
- 1 <= digits.length <= 100
- 0 <= digits[i] <= 9
class Solution {
public:
vector<int> plusOne(vector<int>& digits) {
// vector<int> d(digits);
// 如果上一行去除注释并将下方digits 全部替换为d
// 就不再改变digits了,但时间和空间占用都会大些
int n = digits.size()-1;
for(int i=n;i>=0;--i){ //从最后一位开始判断
if(digits.at(i) == 9){ //如果是9
digits[i] = 0; // 就把本位改为9,转到上一位
}else{
digits[i]++; // 否则本位加一
return digits; // 并返回digits,结束
}
}
digits.insert(digits.begin(),1); //如果循环到第一位了还是9,那就要最前面多加一位1
return digits;
}
};
122. 买卖股票的最佳时机 II
给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。
示例 1:
输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
总利润为 4 + 3 = 7 。
示例 2:
输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
总利润为 4 。
示例 3:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。
提示:
- 1 <= prices.length <= 3 * 104
- 0 <= prices[i] <= 104
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.size() == 1) return 0;
int maxProfit = 0;
vector<int>::iterator slow=prices.begin(), fast = prices.begin()+1;
// 找各个不交叉子增区间的(最大值-最小值)之和
while(fast != prices.end()){
if(*fast > *slow){
while((fast != prices.end()-1) && (*(fast+1) > *fast)) ++fast;
maxProfit += *fast - *slow;
slow = fast+1;
if(slow == prices.end()) break;
fast += 2;
} else {
++slow;++fast;
if(slow == prices.end()) break;
}
}
return maxProfit;
}
};
class Solution {
public:
int maxProfit(vector<int>& prices) {
int ans = 0;
int n = prices.size();
for (int i = 1; i < n; ++i) {
ans += max(0, prices[i] - prices[i - 1]);
}
return ans;
}
};
// 作者:LeetCode-Solution
// 链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/solution/mai-mai-gu-piao-de-zui-jia-shi-ji-ii-by-leetcode-s/
189. 轮转数组
给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。
示例 1:
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
示例 2:
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
提示:
- 1 <= nums.length <= 105
- -231 <= nums[i] <= 231 -1
- 0 <= k <= 105
class Solution {
public:
void rotate(vector<int>& nums, int k) {
if(nums.size() <= k) k %= nums.size();
if(k == 0) return;
int n = (nums.size()-k);
// 把前面的复制插入到后面,再删除前面的
nums.insert(nums.end(), nums.begin(), nums.begin()+n);
nums.erase(nums.begin(), nums.begin()+n);
}
};
class Solution {
public:
void rotate(vector<int>& nums, int k) {
if(nums.size() <= k) k %= nums.size();
if(k == 0) return;
// 三次交换实现,类似反转32bit二进制数那道题
reverse(nums.begin(), nums.end());
reverse(nums.begin(), nums.begin()+k);
reverse(nums.begin()+k, nums.end());
}
};
注意,不要先复制后面的插入到开头再删除后面的,会出现一些问题
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n = nums.size();
k = k % n;
int count = gcd(k, n);
for (int start = 0; start < count; ++start) {
int current = start;
int prev = nums[start];
do {
int next = (current + k) % n;
swap(nums[next], prev);
current = next;
} while (start != current);
}
}
};
// 作者:LeetCode-Solution
// 链接:https://leetcode.cn/problems/rotate-array/solution/xuan-zhuan-shu-zu-by-leetcode-solution-nipk/
217. 存在重复元素
给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false 。
示例 1:
输入:nums = [1,2,3,1] 输出:true
示例 2:
输入:nums = [1,2,3,4] 输出:false
示例 3:
输入:nums = [1,1,1,3,3,4,3,2,4,2] 输出:true
提示:
- 1 <= nums.length <= 105
- -109 <= nums[i] <= 109
class Solution {
public:
bool containsDuplicate(vector<int>& nums) {
// 排序,看是否有连续两个数相同的,也可以看find和rfind同一个数看是否相等
sort(nums.begin(), nums.end());
for(auto i=nums.begin()+1;i!=nums.end();++i){
if(*(i-1) == *i) return true;
}
return false;
}
};
class Solution {
public:
bool containsDuplicate(vector<int>& nums) {
// set不存在重复元素,用nums初始化set,如果元素数少了,就是有重复元素
set<int> se(nums.begin(), nums.end());
return nums.size() != se.size();
}
};
class Solution {
public:
bool containsDuplicate(vector<int>& nums) {
unordered_set<int> us; // map也可以
for(int x: nums){ // 逐个看是否已有,没有就存入,有了就返回true
if(us.find(x) != us.end()) return true;
us.insert(x);
}
return false;
}
};
136. 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1] 输出: 1
示例 2:
输入: [4,1,2,1,2] 输出: 4
class Solution {
public:
int singleNumber(vector<int>& nums) {
// 排序,然后看第一第二个是否相等,第三第四是否相等....
// 找出不等的一对,返回 前一个数
sort(nums.begin(), nums.end());
for(int i=1;i<nums.size();i+=2){
if(nums.at(i) != nums.at(i-1)) return nums.at(i-1);
}
// 前面都是成对的,那就是最后一个
return nums.back();
}
};
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ret = 0;
for (auto e: nums) ret ^= e;
return ret;
}
};
// 注: y^x^x == y 点赞
// 作者:LeetCode-Solution
// 链接:https://leetcode.cn/problems/single-number/solution/zhi-chu-xian-yi-ci-de-shu-zi-by-leetcode-solution/
350. 两个数组的交集 II
给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]
提示:
- 1 <= nums1.length, nums2.length <= 1000
- 0 <= nums1[i], nums2[i] <= 1000
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
unordered_map<int, int> m;
vector<int> r;
for(int i:nums1){
if(m.find(i) != m.end()){
++m[i];
} else {
m[i] = 1;
}
}
for(int j:nums2){
if(m.find(j) != m.end() && m[j]>0){
r.push_back(j);
m[j]--;
}
}
return r;
}
};
进阶:
如果给定的数组已经排好序呢?你将如何优化你的算法?
可以两个指针分别指向两个数组的开头,那个对应的数小,那个指针就向后移动一次,如果相等就将数字加到要返回的数组中并且两个指针都向后移动。直到某个指针到达数组末尾。
如果 nums1 的大小比 nums2 小,哪种方法更优?
如果 nums2 的元素存储在磁盘上,内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
if (nums1.size() > nums2.size()) {
return intersect(nums2, nums1);
}
unordered_map <int, int> m;
for (int num : nums1) {
++m[num];
}
vector<int> intersection;
for (int num : nums2) {
if (m.count(num)) {
intersection.push_back(num);
--m[num];
if (m[num] == 0) {
m.erase(num);
}
}
}
return intersection;
}
};
// 作者:LeetCode-Solution
// 链接:https://leetcode.cn/problems/intersection-of-two-arrays-ii/solution/liang-ge-shu-zu-de-jiao-ji-ii-by-leetcode-solution/
283.移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]
输出: [0]
提示:
- 1 <= nums.length <= 104
- -231 <= nums[i] <= 231 - 1
进阶:你能尽量减少完成的操作次数吗?
class Solution {
public:
void moveZeroes(vector<int>& nums) {
// 遇0则删,并记录0的个数,最后在数组最后补上0
int n = 0;
auto it=nums.begin();
while(it!=nums.end()){
if(*it){
++it;
} else {
it = nums.erase(it);
++n;
}
}
nums.insert(nums.end(),n,0);
}
};
class Solution {
public:
void moveZeroes(vector<int>& nums) {
// 两个指针,快指针遍历整个数组,快指针非零就和慢指针交换且慢指针向后移动,以此来将非零数聚集到前面
int n = nums.size(), left = 0, right = 0;
while (right < n) {
if (nums[right]) {
swap(nums[left], nums[right]);
left++;
}
right++;
}
}
};
// 作者:LeetCode-Solution
// 链接:https://leetcode.cn/problems/move-zeroes/solution/yi-dong-ling-by-leetcode-solution/
1. 两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
提示:
- 2 <= nums.length <= 104
- -109 <= nums[i] <= 109
- -109 <= target <= 109
- 只会存在一个有效答案
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map <int, int> m;
int n=nums.size();
for(int i=0;i<n;++i){
if(m.count(target-nums[i])){
return {m[target-nums[i]],i};
}
m[nums[i]]=i;
}
return {};
}
};
36. 有效的数独
请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。
- 数字 1-9 在每一行只能出现一次。
- 数字 1-9 在每一列只能出现一次。
- 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
注意:
- 一个有效的数独(部分已被填充)不一定是可解的。
- 只需要根据以上规则,验证已经填入的数字是否有效即可。
- 空白格用 ‘.’ 表示。
示例 1:
输入:board =
[[“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:
输入:board =
[[“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 存在, 因此这个数独是无效的。
提示:
- board.length == 9
- board[i].length == 9
- board[i][j] 是一位数字(1-9)或者 ‘.’
class Solution {
public:
bool isValidSudoku(vector<vector<char>>& board) {
bool che[3][9][9]{false}; // bool省空间,存九行、九列、九块的1-9是否已经出现过了
for(int i=0;i<9;++i){
for(int j=0;j<9;++j){
char ch = board[i][j];
if(ch != '.'){
int c = ch-'1';
int bn = i/3+(j/3)*3;
if(che[0][i][c] || che[1][j][c] || che[2][bn][c]) return false; // 如果第二次出现就false
che[0][i][c] = true;
che[1][j][c] = true;
che[2][bn][c] = true;
}
}
}
return true;
}
};
48. 旋转图像
给定一个 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]]
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
// 四次一循环,除去中间可能有一个不变,其余均为四个数依次更换位置,三次交换两个数就可以做到
int n = matrix.size();
int im = n/2;
// 对上方1/4进行处理就可以
for(int i=0;i<im;++i){
int jm = n-i*2-1;
for(int j=0;j<jm;++j){
swap(matrix[i][j+i],matrix[i+j][i+jm]);
swap(matrix[i][j+i],matrix[i+jm-j][i]);
swap(matrix[i+jm-j][i],matrix[i+jm][i+jm-j]);
}
}
}
};