最大数
给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数。
示例 1:
输入:[10,2]
输出:210
示例 2:
输入:[3,30,34,5,9]
输出:9534330
说明: 输出结果可能非常大,所以你需要返回一个字符串而不是整数。
bool comp(string a,string b){
//从大到小
string ab=a+b;
string ba=b+a;
return ab>ba; //这里一定是要大于或小于的时候返回true,不能是大于等于或小于等于
}
class Solution {
public:
string largestNumber(vector<int>& nums) {
if(nums.size()==0) return "0";
vector<string> nums2;
for(int i=0;i<nums.size();i++){
nums2.push_back(to_string(nums[i]));
}
sort(nums2.begin(),nums2.end(),comp);
string res="";
for(int i=0;i<nums2.size();i++){
res=res+nums2[i];
}
if(res[0]=='0') return "0";
return res;
}
};
重新定义比较函数,将两个字符串进行比较,假设a与b进行比较,如果ab大于ba,那么a大于b。
需要注意的是
- 在重写比较函数的时候,一定要是大于或小于的时候返回true,不能是大于等于或小于等于,会导致无穷无尽的比较,最终报错,terminate called after throwing an instance of 'std::length_error'
- 两个字符串也可以直接用大于号小于号进行比较
- 注意 正数、非负数等字眼,充分考虑边界值
摆动排序
给定一个无序的数组 nums
,将它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]...
的顺序。
示例 1:
输入:nums = [1, 5, 1, 1, 6, 4]
输出: 一个可能的答案是[1, 4, 1, 5, 1, 6]
示例 2:
输入:nums = [1, 3, 2, 2, 3, 1]
输出: 一个可能的答案是[2, 3, 1, 3, 1, 2]
说明:
你可以假设所有输入都会得到有效的结果。
进阶:
你能用 O(n) 时间复杂度和 / 或原地 O(1) 额外空间来实现吗?
class Solution {
public:
void wiggleSort(vector<int>& nums) {
//下标为奇数的数要大于下标为偶数的数
vector<int> temp(nums.size());
int even;
if(nums.size()%2==0) even=nums.size()/2;
else even=nums.size()/2+1; //偶数
cout<<"even:"<<even<<endl;
int odd=nums.size()-even; //奇数
cout<<"odd:"<<odd<<endl;
sort(nums.begin(),nums.end());
for(int i=0;i<even;i++){
temp[i*2]=nums[even-1-i];
}
for(int i=0;i<odd;i++){
temp[2*i+1]=nums[nums.size()-1-i];
}
nums=temp;
}
};
从题目给出的样例可以看出是奇数位的值比偶数位的值大,那么可将数组进行排序,前一部分为偶数位的值,后一部分为奇数位的值,由于要求的是大于而不是大于小于,所以都从最后开始取,从前面开始取可能会导致奇偶交界的地方是相等的。
寻找峰值
峰值元素是指其值大于左右相邻值的元素。
给定一个输入数组 nums
,其中 nums[i] ≠ nums[i+1]
,找到峰值元素并返回其索引。
数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞
。
示例 1:
输入: nums = [1,2,3,1]
输出: 2
解释: 3 是峰值元素,你的函数应该返回其索引 2。
示例 2:
输入: nums = [
1,2,1,3,5,6,4]
输出: 1 或 5
解释: 你的函数可以返回索引 1,其峰值元素为 2;
或者返回索引 5, 其峰值元素为 6。
说明:
你的解法应该是 O(logN) 时间复杂度的。
class Solution {
public:
bool finded=false;
int peak=-1;
int findPeakElement(vector<int>& nums) {
//使用分治的方法,查找一个数
if(nums.size()==0) return -1;
else if(nums.size()==1) return 0;
else{
findPeak(0,nums.size()-1,nums);
return peak;
}
}
void findPeak(int begin,int end,vector<int>& nums){
if(finded==true) return;
if(begin>end||begin<0||end>=nums.size()) return;
int mid=(begin+end)/2;
if(mid==0){
if(nums[mid]>nums[mid+1]){
peak=mid;
finded=true;
return;
}
}else if(mid==nums.size()-1){
if(nums[mid]>nums[mid-1]){
peak=mid;
finded=true;
return;
}
}else{
if(nums[mid]>nums[mid+1]&&nums[mid]>nums[mid-1]){
peak=mid;
finded=true;
return;
}
}
findPeak(begin,mid-1,nums);
findPeak(mid+1,end,nums);
}
};
按照二分查找的思路完成
寻找重复数
给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
示例 1:
输入: [1,3,4,2,2]
输出: 2
示例 2:
输入: [3,1,3,4,2]
输出: 3
说明:
- 不能更改原数组(假设数组是只读的)。
- 只能使用额外的 O(1) 的空间。
- 时间复杂度小于 O(n2) 。
- 数组中只有一个重复的数字,但它可能不止重复出现一次。
class Solution {
private:
bool finded=false;
int res=0;
public:
int findDuplicate(vector<int>& nums) {
//思路错了,所有数字在1-n之间,但是并不一定是1-n之间的所有数字都出现
//二分查找,快慢指针找入口
findRange(1,nums.size()-1,nums);
return res;
}
void findRange(int begin,int end,vector<int> nums){
if(finded==true){
return;
}
if(begin>end) return;
int mid=(begin+end)/2;
bool left=count(begin,mid,nums);
bool right=count(mid+1,end,nums);
if(left==false){
if(begin==mid){
res=begin;
finded=true;
}
else findRange(begin,mid,nums);
}
else if(right==false){
if(mid+1==end){
res=end;
finded=true;
}
else findRange(mid+1,end,nums);
}
}
bool count(int begin,int end,vector<int> nums){
//考虑值为begin和end之间是否有重复的数
int count=0;
for(int i=0;i<nums.size();i++){
if(nums[i]>=begin&&nums[i]<=end){
++count;
}
}
//这里需要注意的是,如果一个范围内有重复的数(大于区间距离),那么另一个区间的数就
//会是少的,所以如果按照下面的写法的话是会所有都返回false的
// if(count==end-begin+1) return true;
// else return false;
if(count>end-begin+1) return false;
else return true;
}
};
计算右侧小于当前元素的个数
给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i]
的值是 nums[i]
右侧小于 nums[i]
的元素的数量。
示例:
输入: [5,2,6,1]
输出: [2,1,1,0]
解释:
5 的右侧有 2 个更小的元素 (2 和 1).
2 的右侧仅有 1 个更小的元素 (1).
6 的右侧有 1 个更小的元素 (1).
1 的右侧有 0 个更小的元素.
##暴力遍历无疑是会超时的
###然而,使用归并排序依旧超时了
class Solution {
public:
vector<int> countSmaller(vector<int>& nums) {
//我就知道暴力法会超时
//归并排序,和求解逆序对数比较像
//归并排序也超时
vector<int> res(nums.size(),0);
count(0,nums.size()-1,nums,res);
return res;
}
void count(int begin,int end,vector<int>& nums,vector<int>& res){
if(begin>=end) return;
int mid=(begin+end)/2;
count(begin,mid,nums,res);
count(mid+1,end,nums,res);
for(int i=begin;i<=mid;i++){
for(int j=mid+1;j<=end;j++){
if(nums[i]>nums[j]) ++res[i];
}
}
}
};
计算右侧小于当前元素的个数
给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i]
的值是 nums[i]
右侧小于 nums[i]
的元素的数量。
示例:
输入: [5,2,6,1]
输出: [2,1,1,0]
解释:
5 的右侧有 2 个更小的元素 (2 和 1).
2 的右侧仅有 1 个更小的元素 (1).
6 的右侧有 1 个更小的元素 (1).
1 的右侧有 0 个更小的元素.
我的天,这道题总算是通过了,参考网上的方法,使用树形数组完成,相当快
真的是太巧妙了吧
从后向前遍历数组,用arr存放各个数出现的次数(arr中的数为从小到大的顺序),getsum()得到比当前值小的数的个数,并且使用update逐渐更新数组
class Solution {
public:
int n;
int *arr;
int lowbit(int t){
return t&(-t);
}
int getsum(int pos){
int ans=0;
while(pos){
ans+=arr[pos];
pos-=lowbit(pos);
if(pos==0) break;
}
return ans;
}
void update(int pos,int val){
while(pos<n){ //注意这里要是小于号,否则会堆溢出
arr[pos]+=val;
pos+=lowbit(pos);
if(pos==0) break;
}
}
vector<int> countSmaller(vector<int>& nums) {
n=nums.size();
vector<int> res(n);
if(n==0) return res;
int minn=INT_MAX;
int maxx=INT_MIN;
for(int i=0;i<nums.size();i++){
maxx=max(maxx,nums[i]);
minn=min(minn,nums[i]);
}
n=maxx-minn+2;
arr=new int[n];
memset(arr,0,sizeof(int)*n);
for(int i=nums.size()-1;i>=0;i--){
res[i]=getsum(nums[i]-minn);
update(nums[i]-minn+1,1);
}
return res;
}
};