leetcode模拟面试题
1. 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
解:只出现一次数字,而且还需要线性时间复杂度并且不使用额外空间,那么一定是要考虑遍历一次数组来完成操作。
关键字:某个元素只出现一次,而其他出现两次。 可以想到 ^ 异或运算符,两个相同的数字异或得 1 ,任何数字和 1 异或都得到本身
如此得出将数组中的所有数字全部异或一遍即可得到答案
class Solution {
public:
int singleNumber(vector<int>& nums) {
if(nums.size() == 0)
return 0;
int num = nums[0];
for(int i=1 ;i<nums.size() ;++i)
{
num ^= nums[i];
}
return num;
}
};
2. 多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入: [3,2,3]
输出: 3
示例 2:
输入: [2,2,1,1,1,2,2]
输出: 2
解:一个元素在数组中出现次数大于n/2,那么即可定义一个变量ans来存储遍历一次数组后所得的元素,遍历的过程相当于抵消的过程,如果nums[i]不等于ans,那么次数-1,当次数等于0时,ans替换为nums[i],最后剩下来的元素也就一定是出现次数大于n/2的元素。
class Solution {
public:
int majorityElement(vector<int>& nums) {
int ans = nums[0];
int times = 1;
for(int i=1 ;i<nums.size() ;++i)
{
if(nums[i] != ans)
{
--times;
if(times == 0)
{
ans = nums[i];
times = 1;
}
}
else
++times;
}
return ans;
}
};
3. 搜索二维矩阵 II
编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target。该矩阵具有以下特性:
每行的元素从左到右升序排列。
每列的元素从上到下升序排列。
示例:
现有矩阵 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。
给定 target = 20,返回 false。
解:此题的关键在于从那个位置开始进行搜索,如果只是暴力搜索的话时间复杂度是O(n^2),虽然能够解决问题但是显然不是很好的方法。
因为矩阵是有排序顺序的,所以根据排序规则,从左下角和右上角开始搜索,其行和列两个方向是不同的排序规则,一个升序一个降序,从而可以确定target的行和列。如果从左上角和右下角搜索,则无法确定。
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int rows = matrix.size();
if(rows == 0)
return 0;
int cols = matrix[0].size();
int i = rows-1;
int j = 0;
while(i >= 0 && j < cols)
{
if(matrix[i][j] > target)
--i;
else if(matrix[i][j] < target)
++j;
else
return true;
}
return false;
}
};
4. 合并两个有序数组
给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
说明:
初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
示例:
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
输出: [1,2,2,3,5,6]
解:因为从数组的前端往后面放数会有数组中的数字整体向后移动的问题,那么就要从大向小向nums1中添加数字。
使用3个指针进行操作 i,j,k , i 指向nums1非0的末尾, j 指向nums2的末尾,k 指向nums1的末尾。比较nums1[i]和nums2[j] ,两个值谁大谁就放在nums1[k]的位置上,当 i 和 j 其中有一个小于0的时候循环结束。循环结束时有两种情况,一个是 i 还大于等于0,此时不用再做操作,因为 i 指向的就是nums1中的数字,不用再移动;另一种情况是 j 大于等于0,此时还需要将剩下的nums2的数字拷贝到nums1中去。
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
if(m == 0)
nums1 = nums2;
if(n == 0)
return;
int i=m-1 ,j=n-1,k = m+n-1;
while(i >= 0 && j >= 0)
{
if(nums2[j] > nums1[i])
{
nums1[k] = nums2[j];
--j;
--k;
}
else
{
nums1[k] = nums1[i];
--i;
--k;
}
}
while(k>=0 && j>=0)
{
nums1[k--] = nums2[j--];
}
}
};