C++leetcode刷题记录
参考资料:
http://www.cplusplus.com/reference/unordered_map/unordered_map/
C++ Primer
1:高度检查器
学校在拍年度纪念照时,一般要求学生按照 非递减 的高度顺序排列。
请你返回能让所有学生以 非递减 高度排列的最小必要移动人数。
思路:
插入排序+检查几位不同
class Solution {
public:
int heightChecker(vector<int>& heights) {
vector<int> heights_copy(heights);
for(int i=0;i<heights.size();i++)
{
//若后面一个元素比其前面一个元素小,
//则将这两个元素交换位置,
for(int j = i - 1; j >= 0; j--)
{
if(heights[j+1]<heights[j])
{
int x;
x=heights[j];
heights[j]=heights[j+1];
heights[j+1]=x;
}
}
}
int count=0;
for(int i=0;i<heights.size();i++)
{
if(heights[i]!=heights_copy[i])
count++;
}
return count;
}
};
在看了解题思路后,差不多就是插入排序+检查 看到了一个
vector<int> res;
sort(res.begin(), res.end());
解释:
sort(begin, end, cmp),其中begin为指向待sort()的数组的第一个元素的指针,end为指向待sort()的数组的最后一个元素的下一个位置的指针,cmp参数为排序准则,如果没有的话,默认以非降序排序。
2:剑指offer 53 0~n-1中缺失的数字
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
思路;搜索问题:
不缺数字的求和-数组求和=少的数字 OR 二分 OR 下标和数字没对上的那个数
class Solution {
public:
int missingNumber(vector<int>& nums) {
int sum =0;
for(int i=0;i<nums.size();i++)
{
sum+=nums[i];
}
int sum1 =(0+(int)nums.size())*((int)nums.size()+1)/2-sum;
return sum1;
}
};
二分法(在数组的搜索问题中,首先需要想到的就是搜索方法)
左子数组的都是下标和数字是一样的,右子数组的下标和数字是不一样的。
class Solution {
public:
int missingNumber(vector<int>& nums) {
int n = nums.size();
int left = 0, right = n - 1;
while(left < right){
int mid = (right+left) / 2;
if(nums[mid] == mid){
left = mid + 1;
}else
right = mid;
}
return left == nums[left] ? left + 1 : left;
}
};
3:350.两个数组的交集 Ⅱ
给定两个数组,编写一个函数来计算它们的交集。
说明:
输出结果中每个元素出现的次数,应与元素在两个数组中出现次数的最小值一致。
我们可以不考虑输出结果的顺序。
思路:哈希表 OR 排序之后两个指针遍历
思路1:
哈希表 在C++ STL中命名为 unordered_map<A,B>;
把短的数组存一编,然后使用长的遍历去找。找到输出,并减少次数。
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> mymap;
for(int num:nums1)
{
++mymap[num];
}
vector<int> output;
for(int num:nums2)
{
if(mymap[num]!=0)
{
output.push_back(num);
--mymap[num];
}
}
return output;
}
};
思路二:
先排序,再使用两个指针分别指。小的值移动一个。如果遇到一样大,一起移动。(排序使用sort)使用iterator 来遍历vector .要注意的是iterator 是一个指针哦~vector本质上是一个数组。
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
sort(nums1.begin(),nums1.end());
sort(nums2.begin(),nums2.end());
vector <int>::iterator it1,it2;
it1=nums1.begin();
it2=nums2.begin();
vector <int> output;
while(it1!=nums1.end()&&it2!=nums2.end())
{
if(*it1!=*it2)
{
*it1<*it2?it1++:it2++;
}
else
{
output.push_back(*it1);
it1++;
it2++;
}
}
return output;
}
};
4:面试题 16.04 井字游戏
设计一个算法,判断玩家是否赢了井字游戏。输入是一个 N x N 的数组棋盘,由字符" ",“X"和"O"组成,其中字符” "代表一个空位。
以下是井字游戏的规则:
玩家轮流将字符放入空位(" “)中。
第一个玩家总是放字符"O”,且第二个玩家总是放字符"X"。
"X"和"O"只允许放置在空位中,不允许对已放有字符的位置进行填充。
当有N个相同(且非空)的字符填充任何行、列或对角线时,游戏结束,对应该字符的玩家获胜。
当所有位置非空时,也算为游戏结束。
如果游戏结束,玩家不允许再放置字符。
如果游戏存在获胜者,就返回该游戏的获胜者使用的字符(“X"或"O”);如果游戏以平局结束,则返回 “Draw”;如果仍会有行动(游戏未结束),则返回 “Pending”。
思路:分类。有输赢无非就是行、列、对角线有一个是元素非空格的。然后如果没有,判断空否,有空就是Pending,没有就是Draw。(自己写的一直编译不过
vector
可能需要去看下string的访问方式)下面为leetcode上的一个思路类似的答案。另一种求和的方式感觉会存在bug。
class Solution {
public:
string tictactoe(vector<string>& board) {
size_t count_x = 0, count_o = 0, len = board.size();
for (const auto& str : board)
for (const auto& ch : str) {
if (ch == 'X') ++count_x;
else if (ch == 'O') ++count_o;
}
if (isWin('X', board, len)) return "X";
if (isWin('O', board, len)) return "O";
//是否没下满棋盘
return count_x + count_o < len * len ? "Pending" : "Draw";
}
bool isWin(const char& ch, vector<string>& board, const size_t& len) {
//横向
for (size_t i = 0; i < len; ++i) {
for (size_t j = 0; j < len; ++j) {
if (board[i][j] != ch) break;
else if(j == len - 1) return true;
}
}
//纵向
for (size_t j = 0; j < len; ++j) {
for (size_t i = 0; i < len; ++i) {
if (board[i][j] != ch) break;
else if(i == len - 1) return true;
}
}
//正对角线
bool found = true;
for (size_t i = 0; i < len; ++i)
if (board[i][i] != ch) {
found = false;
break;
}
if (found) return true;
//逆对角线
found = true;
for (size_t i = 0; i < len; ++i)
if (board[i][len - 1 - i] != ch) {
found = false;
break;
}
return found;
}
};
5 大小为K且平均值大于等于阈值的子数组数目
给你一个整数数组 arr 和两个整数 k 和 threshold 。
请你返回长度为 k 且平均值大于等于 threshold 的子数组数目。
class Solution {
public:
int numOfSubarrays(vector<int>& arr, int k, int threshold) {
int target = threshold*k;
int flag =0;
vector<int>::iterator it;
if(arr.size()<k)
{
return -1;
}
for(it=arr.begin();it!=arr.end()-k+1;it++)
{
long sum=-target;
for(int i=0;i<k;i++)
{
sum+=*(it+i);
}
if (sum >=0)
++flag;
}
return flag;
}
};
我的代码在测试用例上没有问题,但是在提交过程中最后一个用例 超出时间限制,要是有人看懂为什么了可以评论一下。
迭代器的取值操作 参考
然后看了别人的思路。
思路:
step1 : 取出前k个数求和,然后减去k*threshold ,如果结果大于0,说明符合要求。
step2 : 指针后移一位,用后移一位的值减去移动之前的第一位的值,再加上上次减法的结果,如果大于0,说明符合要求
整体思路没有除法,只有增量的加减,而且加减数值非常小。
class Solution {
public:
int numOfSubarrays(vector<int>& arr, int k, int threshold) {
int sum=0,result=0;
int sumTarget=k*threshold;
for(int i=0;i<k;i++)
{
sum+=arr[i];
}
int adder=sum-sumTarget;
if(adder>=0)
{
result++;
}
for(int i=0;i<arr.size()-k;i++)
{
adder=adder-arr[i]+arr[i+k];
if(adder>=0)
{
result++;
}
}
return result;
}
};
链接:https://leetcode-cn.com/problems/number-of-sub-arrays-of-size-k-and-average-greater-than-or-equal-to-threshold/solution/ci-ti-zui-you-jie-hua-dong-chuang-kou-jia-dong-tai/
来源:力扣(LeetCode)
感觉很妙
6 剑指offer 45.把数组排成最小的数
输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
TIPS:int转string的一些方法。
int i = 100;
方法一:String s1 = i + " ";
方法二:String s2 = String.valueof(i);
方法三(先转换为Integer类型,在调用toString方法)
Intrger i2 = new interger(i);
String s3 = i2.toString();
方法四:String s4 = Integer.toString(i);
[](string& s1, string& s2){return s1 + s2 < s2 + s1;}
一个lambda表达式的写法,重定义了排序的顺序,如果s1+s2<s2+s1认为 s1 < s2
https://www.jianshu.com/p/d686ad9de817
class Solution {
public:
string minNumber(vector<int>& nums) {
vector<string>strs;
string ans;
for(int i = 0; i < nums.size(); i ++){
strs.push_back(to_string(nums[i]));
}
sort(strs.begin(), strs.end(), [](string& s1, string& s2){return s1 + s2 < s2 + s1;});
for(int i = 0; i < strs.size(); i ++)
ans += strs[i];
return ans;
}
};
学习一下lamada
7 两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍