1.给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
输入: [2,2,1] 输出: 1
解:采用异或^操作,即相异才为1,相同为0 ,两个相同元素相与运算后为0 ,剩下的那一个元素与只出现了一次的元素一定不同,则异或后一定为只出现了一次的那个值。
#include <iostream>
#include<vector>
using namespace std;
class Solution {
public:
int singleNumber(vector<int>& nums) {
int result = 0;
for (int i = 0; i < nums.size(); i++)
result ^= nums[i];//异或运算,相同为0,不同为1
return result;
}
};
int main()
{
Solution s1;
vector<int> a{ 3,3,5 };
cout << s1.singleNumber(a);
}
2.给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋
的元素。
输入: [3,2,3] 输出: 3
解:题目中说的众数是出现次数大于了n/2次的,即占了一半以上,因此可以进行一个排序,然后取中间那一个元素即为众数
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Solution {
public:
int singleNumber(vector<int>& nums) {
sort(nums.begin(), nums.end());
return nums[nums.size() / 2];
}
};
int main()
{
Solution s1;
vector<int> a{ 3,3,5,3,1,23,4,53,2,1,1,1 ,1,1,1,1,1};
cout << s1.singleNumber(a);
}
3.编写一个高效的算法来搜索 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
。
解:根据每行的元素从左到右升序排列,每列的元素从上到下升序排列这两个特点可以得知右上角的元素一定是较大的,从右上角开始对target进行搜索,若target值等于右上角的值则搜索成功,若target值小于右上角,即证明target不在右上角值的所在列,则可以去掉该列。若target值大于右上角,即证明了target的值在该列的行向量里面,转而进行从上向下行搜索。
#include<vector>
#include<algorithm>
using namespace std;
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if (matrix.size() == 0) {
return false;
}
int i = 0, j = matrix[0].size() - 1;
while (i < (int)matrix.size() && j >= 0)
{
if (matrix[i][j] == target)
{
return true;
}
else if (matrix[i][j] > target)
{
--j;
}
else
{
++i;
}
}
return false;
}
};
int main()
{
Solution s1;
vector<vector<int>> a{ {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} };
cout << s1.searchMatrix(a,5);
}
4. 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。
说明:
初始化 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]
解:先将nums2的元素插入到nums1中,再进行一个排序即可
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int j = 0;
for (int i = m; i < m+n; i++)
{
nums1[i] = nums2[j++];
}
sort(nums1.begin(), nums1.end());
for (vector<int>::iterator it = nums1.begin(); it != nums1.end(); it++)
{
cout << (*it) << endl;
}
}
};
int main()
{
Solution s1;
vector<int> a1{ 1,2,3,0,0,0 }, a2{ 2,5,6 };
s1.merge(a1,3,a2,3);
}
5.你将获得 K
个鸡蛋,并可以使用一栋从 1
到 N
共有 N
层楼的建筑。每个蛋的功能都是一样的,如果一个蛋碎了,你就不能再把它掉下去。你知道存在楼层 F
,满足 0 <= F <= N
任何从高于 F
的楼层落下的鸡蛋都会碎,从 F
楼层或比它低的楼层落下的鸡蛋都不会破。每次移动,你可以取一个鸡蛋(如果你有完整的鸡蛋)并把它从任一楼层 X
扔下(满足 1 <= X <= N
)。你的目标是确切地知道 F
的值是多少。无论 F
的初始值如何,你确定 F
的值的最小移动次数是多少?
示例 1:
输入:K = 1, N = 2 输出:2 解释: 鸡蛋从 1 楼掉落。如果它碎了,我们肯定知道 F = 0 。 否则,鸡蛋从 2 楼掉落。如果它碎了,我们肯定知道 F = 1 。 如果它没碎,那么我们肯定知道 F = 2 。 因此,在最坏的情况下我们需要移动 2 次以确定 F 是多少。
示例 2:
输入:K = 2, N = 6 输出:3
解:
假设我们第一个鸡蛋扔出的位置在第X层(1<=X<=M),会出现两种情况:
1.第一个鸡蛋没碎
那么剩余的M-X层楼,剩余N个鸡蛋,可以转变为下面的函数:
F(M-X,N)+ 1,1<=X<=M
2.第一个鸡蛋碎了
那么只剩下从1层到X-1层楼需要尝试,剩余的鸡蛋数量是N-1,可以转变为下面的函数:
F(X-1,N-1) + 1,1<=X<=M
整体而言,我们要求出的是 N层楼 / K个鸡蛋 条件下,最大尝试次数最小的解,所以这个题目的状态转移方程式如下:
X可以为1......N,所以有M个Max( F(N-X,K)+ 1, F(X-1,K-1) + 1)的值,最终F(N,K)是这M个值中的最小值,即最优解
F(N,K)= Min(Max( F(N-X,K)+ 1, F(X-1,K-1) + 1)),1<=X<=N
我们使用record数组来记录最多检测的楼层数,move代表移动次数,K代表鸡蛋个数,N代表楼层数。即设函数:
层数n=黑箱子fun函数f(x,k)表示移动x次,k个鸡蛋能够检测到的最高层数。
假设从n0+1层上扔下一个鸡蛋:
1.若鸡蛋碎了,则剩下x-1次机会和k-1个鸡蛋来检测n0层楼
2.若鸡蛋没有碎,则剩下x-1次机会和k个鸡蛋来检测n1层楼.即通过x-1次机会可以检测出1到n0+n1+1楼层的范围。
用函数表示:
状态转移方程:f(x,k) = f(x-1,k-1)+f(x-1,k)+1
即:本次fun(k)检测的楼层数=上次fun(k-1)鸡蛋碎掉情况下检测的楼层数+上次fun(k)鸡蛋没有碎掉情况下检测的楼层数+1,1代表本次加了一层楼层来进行检测。
算法思想:移动了move次后,能够检测到的最大楼层数超过给定的楼层数则跳出循环,返回move值,否则利用状态转移方程进行楼层数累加统计。
#include <iostream>
#include<vector>
using namespace std;
class Solution {
public:
int superEggDrop(int K, int N) {
//record[i]=n表示第i个鸡蛋经过moves的移动,最多检测到的层数
vector<int>record(K + 1, 0);//包含0个鸡蛋的情况,所以需要申请K+1个空间
int move = 0;
while (record[K] < N)//当record[K]大于等于N的时候就退出循环
{
for (int i = K; i >= 1; i--)
/*假设record[k-1]=n0,record[k]=n1,
首先检测,从第 n0+1 楼丢下鸡蛋会不会破。
如果鸡蛋破了,F 一定是在 [1:n0] 楼中,利用剩下的 moves-1 次机会和 k-1 个鸡蛋,可以把 F 找出来.
如果鸡蛋没破,假如 F 在 [n0+2:n0+n1+1] 楼中,利用剩下的 moves-1 次机会和 k 个鸡蛋,也可以把 F 找出来。
所以,当有 moves 个放置机会和 k 个鸡蛋的时候,F 在 [1, n0+n1+1] 中的任何一楼,都能够被检测出来。*/
record[i] += record[i - 1] + 1;
move++;
}
return move;//返回需要的尝试次数
}
};
int main()
{
Solution s1;
cout<<s1.superEggDrop(2,3);
}