1.例题
先看一道题,将一个乱序数组排序后,将前面一半翻转,将后面一半翻转,例如:
输入:4,1,2,3,5
输出:3,2,1,5,4
输入:5,2,3,1
输出:2,1,5,3
其实这个题目很简单,只需要将数组排序后,分为前后两部分,分别翻转即可。
void solution(vector<int> &nums)
{
int n = nums.size();
//排序
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n - 1 - i; ++j)
{
if (nums[j + 1] < nums[j])
{
swap(nums[j + 1], nums[j]);
}
}
}
//翻转
for (int i = 0; i < n / 4; ++i)
{
swap(nums[i], nums[(n - 1) / 2 - i]);
swap(nums[(n + 1) / 2 + i], nums[n - 1 - i]);
}
}
2.引入概念
基本上上面的做法是大家常规的一种做法,但是有其他也比较简洁的做法吗?
上面的算法分为了:1.排序, 2.翻转两个步骤。有没有可能将两个步骤合并一起做呢?
我们先看,翻转实际上是对原数组的一种映射:
1,2,3,4,5 ———> 3,2,1,5,4
映射为: 0→2,1→1,2→0,3→4,4→3
1,2,3,4 ———> 2,1,4,3
映射为: 0→1,1→0,2→3,3→2
如果将原来的索引记为x,映射后的索引为y,不难得到映射关系为:
y = f ( x ) = ( ( n − 1 ) / 2 − x ) % n y =f(x)=((n-1)/2-x)\%n y=f(x)=((n−1)/2−x)%n
我们可以将新索引看做是一个新的数组b,那么:
a [ x ] = b [ f ( x ) ] a[x] = b[f(x)] a[x]=b[f(x)]
因为要排序,所以我们知道: a [ j ] < a [ i ] ( < i ) a[j]<a[i] ( < i) a[j]<a[i](<i) ,所以: b [ f ( j ) ] < b [ f ( i ) ] ( < i ) b[f(j)]<b[f(i)] ( < i) b[f(j)]<b[f(i)](<i)
那么我们只需要对: b [ f ( j ) ] b[f(j)] b[f(j)] 排序即可。
void solution(vector<int> &nums)
{
int n = nums.size();
#define a(i) nums[((3*n-1)/2 - (i))%n]
//排序
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n - 1 - i; ++j)
{
if (a(j+1) < a(j))
{
swap(a(j + 1), a(j));
}
}
}
}