LeetCode954二倍数对数组
问题:二倍数对数组
给定一个长度为偶数的整数数组 A
,只有对 A
进行重组后可以满足 “对于每个 0 <= i < len(A) / 2
,都有 A[2 * i + 1] = 2 * A[2 * i]
” 时,返回 true
;否则,返回 false
。
示例 1:
输入:[3,1,3,6]
输出:false
示例 2:
输入:[2,1,2,6]
输出:false
示例 3:
输入:[4,-2,2,-4]
输出:true
解释:我们可以用 [-2,-4] 和 [2,4] 这两组组成 [-2,-4,2,4] 或是 [2,4,-2,-4]
示例 4:
输入:[1,2,4,16,8,4]
输出:false
提示:
0 <= A.length <= 30000
A.length
为偶数-100000 <= A[i] <= 100000
链接:https://leetcode-cn.com/contest/weekly-contest-114/problems/array-of-doubled-pairs/
分析:
题目要求看给出的数组能否通过重新排序,使的所有的偶数位置值是前一个的奇数值的二倍。
那么可以通过将数据分为负数和非负数两组,分组的原因是方便处理,对于非负数,直接递增排序正向处理,对于负数,排序后需要反向处理。关键看绝对值,处理逻辑是一样的。
以非负数为例:
排序后最小的值肯定是放在奇数位,那么在后面查找他的2倍是否存在,如果不存在可以直接结束返回false
如果存在,则需要将该数字移除,因为每个数字只能用到一次。
比如给出的例子中第一组排序后是 1 3 3 6 ,1 的2倍2不存在,false
第二组: 1 2 2 6,1的二倍2存在,移除2,得到1 2 6,处理下一个数据2,2的2倍4不存在,false
第三组分为-4 -2和2 4 两组,都对应存在,true
第四组,排序后 1 2 4 4 8 16
1-> 2 存在,移除2数组变为1 4 4 8 16
处理下一个4,4->8 存在,移除8得到 1 4 4 16
处理下一个4,8不存在,false
AC Code:
class Solution {
public:
bool canReorderDoubled(vector<int>& A) {
bool ret = true;
//首先正负分开
vector<int> Pvec;
vector<int> Nvec;
for (unsigned int i = ; i < A.size(); i++)
{
if (A[i] < )
{
Nvec.emplace_back(-*A[i]);
//Pvec.emplace_back(-1*A[i]);
}
else
{
Pvec.emplace_back(A[i]);
}
}
if (Pvec.size() % != )
{
return false;
}
sort(Pvec.begin(), Pvec.end());
int limit = Pvec.size() / ;
for (unsigned int i = ; i < limit;i++)
{
if (find(Pvec.begin() + i + , Pvec.end(), * Pvec[i]) != Pvec.end())
{
Pvec.erase(find(Pvec.begin() + i + , Pvec.end(), * Pvec[i]));
}
else
{
return false;
}
}
sort(Nvec.begin(), Nvec.end());
limit = Nvec.size() / ;
for (unsigned int i = ; i < limit;i ++)
{
if (find(Nvec.begin() + i + , Nvec.end(), * Nvec[i]) != Nvec.end())
{
Nvec.erase(find(Nvec.begin() + i + , Nvec.end(), * Nvec[i]));
}
else
{
return false;
}
}
return true;
}
};
其他:
1.sort 默认升序,对于负数可以通过乘以-1转换为整数,之前看别人的一个解答学到的,可以省去编写自定义排序函数。
2.vector中查看某个元素是否存在,通过find(.begin(),.end(),value),如果没找到,返回end(),如果找到了,返回对应的迭代器值(iterator)
3,vector 中删除元素通过索引,如果本身就是iterator,可以直接删除erase(iterator),如果是个index 数字,可以通过erase(.begin()+index)
4,第一code:
#pragma GCC optimize("O3", "unroll-loops")
// God Help me !!
#include <bits/stdc++.h>
using namespace std;
// #define watch(x) cout << (#x) << " is " << (x) << endl #define FILES freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout)
#define FAST ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define FIXED cout << fixed << setprecision(20)
#define RANDOM srand(time(nullptr))
// #define int long long
#define MOD 1000000007
#define sz(a) (ll)a.size()
#define pll pair<ll,ll>
#define rep(i,a,b) for(int i=(int)a;i<(int)b;i++)
#define sep(i,a,b) for(int i=(int)a;i>=(int)b;i--)
#define mll map<int,int>
#define vl vector<int>
#define pb push_back
#define lb lower_bound
#define ub upper_bound
#define all(a) a.begin(),a.end()
#define F first
#define S second
#define endl "\n"
#define MAXN6 3000005
#define MAXN3 3005
#define MAXN5 300005 #define watch(...) ZZ(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1> void ZZ(const char* name, Arg1&& arg1){std::cerr << name << " = " << arg1 << endl;}
template <typename Arg1, typename... Args>void ZZ(const char* names, Arg1&& arg1, Args&&... args)
{
const char* comma = strchr(names + , ',');
std::cerr.write(names, comma - names) << " = " << arg1;
ZZ(comma, args...);
} class Solution {
public:
bool canReorderDoubled(vector<int>& A) {
int positive[], negative[];
memset(positive, , sizeof(positive));
memset(negative, , sizeof(negative));
for (int x: A) {
if (x >= ) positive[x]++;
else negative[-x]++;
}
if (positive[] % != ) return false;
for (int i = ; i <= ; i++) {
if (positive[i] != ) {
if (positive[i*] < positive[i]) return false;
positive[i*] -= positive[i];
}
}
for (int i = ; i <= ; i++) {
if (negative[i] != ) {
if (negative[i*] < negative[i]) return false;
negative[i*] -= negative[i];
}
}
return true;
}
};
看到第一code 用来桶的那种方式 ,通过申请足够大的数组,下标就是值,删除通过--实现,而vector中删除需要移动大量数据,随意AC虽然过了,时间800+
完赛后QQ群里面有提到这个题 其实核心思路就是分组,排序, 查找元素是否存在以及删除。
那么可以通过map来做,map存储出现的数字以及个数 ,key是数字,value是数字个数,如果数字被用过了,value--,通过这种方式模拟删除。
这样也能AC,而且时间从800+降到96,虽然时间和很多因素有关, 比如服务器状态、测试数据等,但是下降一个数量级还是很能说明问题的。
map实现:
class Solution {
public:
bool canReorderDoubled(vector<int>& A) {
bool ret = true;
map<int, int> Ndata;
map<int, int> Pdata;
int Nnum = ;
for (int i : A)
{
if (i >= )
{
if (Pdata.find(i) != Pdata.end())
{
Pdata[i]++;
}
else
{
Pdata[i] = ;
}
}
else
{
Nnum++;
if (Ndata.find(-*i) != Ndata.end())
{
Ndata[- * i]++;
}
else
{
Ndata[- * i] = ;
}
}
} if (Nnum % != )
{
return false;
}
//处理非负数
map<int, int>::iterator it = Pdata.begin();
int Limit = (A.size()-Nnum) / ;
for (unsigned int i = ; i < Limit; )
{
if ((*it).second == )
{
it++;
continue;
}
int tmpdata = (*it).first;
(*it).second--;
map<int, int>::iterator tmpit;
tmpit = Pdata.find( * (*it).first);
if (tmpit == Pdata.end() || (*tmpit).second==)
{
return false;
}
else
{
(*tmpit).second--;
}
if ((*it).second == )
{
it++;
}
i++;
} it = Ndata.begin();
Limit = Nnum / ;
for (unsigned int i = ; i < Limit;)
{
if ((*it).second == )
{
it++;
continue;
}
int tmpdata = (*it).first;
(*it).second--;
map<int, int>::iterator tmpit;
tmpit = Ndata.find( * (*it).first);
if (tmpit == Ndata.end() || (*tmpit).second == )
{
return false;
}
else
{
(*tmpit).second--;
}
if ((*it).second == )
{
it++;
}
i++;
} return ret;
}
};
一段时间不用map,手生了。
a.1 map个数是值的个数,这一个题中直接用map的size得不到正负数个数,需要value累加或者通过额外的一个变量记录
a.2 如果因为个数为零跳过,那么index i不应增加,所以i的改变时机要放到后面合适的地方,而不是for内
a.3 如果数据涉及到底层的移动变换等,最好能够避免,是在避免不了也尽量集中处理 ,记得之前看到一本书提到C++的一些高级特性的时候有提到这个,一时想不起来的,书读百遍,有时间还是得在读一遍。
a.4使用的C++,感觉自己用的这套测试测试函数挺不错的,再也不用通过OJ debug了,而且能够回归测试,避免修改过后顾头不顾尾,记下来,有需要的可以拿去。
比如对于954的测试:
void test954()
{
Solution954 S;
vector<int> A;
bool ans;
bool tans; A = vector<int>{ ,,,,, };
tans = false;
ans = S.canReorderDoubled(A);
cout << "ans:" << ans << " tans:" << tans << " ### " << (ans == tans) << endl; A = vector<int>{ ,,, };
tans = false;
ans = S.canReorderDoubled(A);
cout << "ans:" << ans << " tans:" << tans << " ### " << (ans == tans) << endl; A = vector<int>{ ,,,,,,,};
tans = true;
ans = S.canReorderDoubled(A);
cout << "ans:" << ans << " tans:" << tans << " ### " << (ans == tans) << endl; A = vector<int>{ ,,, };
tans = false;
ans = S.canReorderDoubled(A);
cout << "ans:" << ans << " tans:" << tans << " ### " << (ans == tans) << endl; A = vector<int>{ ,-,,- };
tans = true;
ans = S.canReorderDoubled(A);
cout << "ans:" << ans << " tans:" << tans << " ### " << (ans == tans) << endl; A = vector<int>{ ,,,,, };
tans = false;
ans = S.canReorderDoubled(A);
cout << "ans:" << ans << " tans:" << tans << " ### " << (ans == tans) << endl;
}
如果有新的测试数据只需要加进去就行。如果用来测试新的类,只需要根据需要设定数据类型,返回值类型,然后在具体的测试用例里面设置就可以了。如果输出目标答案tans和时机答案ans一致,则测试通过。如果是一些符合数据,需要自己编写判断是否相等的函数。
LeetCode954二倍数对数组的更多相关文章
- [Swift]LeetCode954. 二倍数对数组 | Array of Doubled Pairs
Given an array of integers A with even length, return true if and only if it is possible to reorder ...
- PHP二维关联数组的遍历方式
采用foreach循环对二维索引数组进行遍历,相对来讲速度更快,效率更高,foreach循环是PHP中专门用来循环数组的.实例也相对简单,多加练习,想清楚程序运行逻辑即可. <?php $arr ...
- C++ 指针二维数组, C++二维指针数组笔记
C++ 二维动态数组 一. 已知第一维 #include <iostream> using namespace std; int main(int argc, char const *ar ...
- Task 4.4二维环形数组求最大子矩阵之和
任务: (1)输入一个二维整形数组,数组里有正数也有负数. (2)二维数组首尾相接,象个一条首尾相接带子一样. (3)数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. (4)求所有子数 ...
- 子串查询(二维前缀数组) 2018"百度之星"程序设计大赛 - 资格赛
子串查询 Time Limit: 3500/3000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Subm ...
- 二维字符数组利用gets()函数输入
举例: ][]; ;i<;i++) gets(a[i]); a是二维字符数组的数组名,相当于一维数组的指针, 所以a[i]就相当于指向第i个数组的指针,类型就相当于char *,相当于字符串.
- 分配一维动态数组or 二维动态数组的方法以及学习 new 方法or vector
先来个开胃菜 // 使用new动态分配存储空间 #include<iostream> using std::cout; int main() { // 第1种方式 int *a=new i ...
- fastJson在java后台转换json格式数据探究(二)--处理数组/List/Map
作者:buster2014 推荐:长安散人 fastJson在java后台转换json格式数据探究(二)--处理数组/List/Map JSON字符串与Java对象的转换 1.将Java对象或Java ...
- 计算机二级-C语言-程序填空题-190109记录-对二维字符串数组的处理
//给定程序,函数fun的功能是:求出形参ss所指字符串数组中最长字符串的长度,将其余字符串右边用字符*补齐,使其与最长的字符串等长.ss所指字符串数组中共有M个字符串,且串长<N. //重难点 ...
随机推荐
- 16-----client、offset、scroll 系列
1.client 代码如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> ...
- java——模拟新浪微博用户注册
1.创建用户类,重写HashCode()和equals()方法: import java.util.*; public class User{ private String name; private ...
- C# this索引器
- Python package和folder
在Python项目里面的区分,按照如下规定进行: 1.严格区分包和文件夹.包的定义就是包含__init__.py的文件夹. 如果没有__init__.py,那么就是普通的文件夹. 2.导入packag ...
- Spring Cloud微服务初探
学习初衷 因为加了不少优秀的知识星球,结交了更多的小伙伴,加了更多的群,每每在自我介绍的时候,都说自己是Android & Java攻城狮. 然鹅,有的小伙伴就来问了,你是搞Java的,那对S ...
- [Windows] 一些简单的CMD命令
开始菜单中的“运行”是通向程序的快捷途径,输入特定的命令后,即可快速的打开Windows搜索的大部分程序,熟练的运用它,将给我们的操作带来诸多便捷. winver 检查Windows版本 wmimgm ...
- VS2017无法进入断点调试且移动到breakpoint上的时候报错“breakpoint will not currently be hit. the source code is different from original version. ”
我尝试了网上的很多其他办法也翻阅了很多外网资源,这些方法并不能解决我的问题 当然我非常震惊正当我尝试着在stack overflow上发表评论交流一下究竟如何解决的时候,却发现有方法灵验了 ,但是每个 ...
- Photoshop之切图
基本(繁琐)操作: 切JPG图(即带背景的图): 1. 选切片工具(另外,切片选择工具能选择切片和删除切片),切 2. 存储为Web所用格式(快捷键Ctrl + Shi ...
- Eucalyptus常用查询命令
前言: Elastic Utility Computing Architecture for Linking Your Programs To Useful Systems (Eucalyptus) ...
- C#cmd执行命令隐藏窗口,并保持程序一直运行
把要执行的cmd命令放入一个bat文件里,然后执行: //Process p = Process.Start(bPath); Process pro = new Process();pro.Start ...