【LeetCode & 剑指offer刷题】查找与排序题14:Wiggle Sort(系列)
【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)
Wiggle Sort II
Given an unsorted array
nums
, reorder it such that
nums[0] < nums[1] > nums[2] < nums[3]...
.
Example 1:
Input:
nums = [1, 5, 1, 1, 6, 4]
Output:
One possible answer is
[1, 4, 1, 5, 1, 6]
.
Example 2:
Input:
nums = [1, 3, 2, 2, 3, 1]
Output:
One possible answer is
[2, 3, 1, 3, 1, 2]
.
Note:
You may assume all input has valid answer.
Follow Up:
Can you do it in O(n) time and/or in-place with O(1) extra space?
C++
//问题:摆动排序,a[0] < a[1] > a[2] < a[3]...
//??没看懂,以后再看
//方法二:利用快排中一步(nth_element函数)将序列分成两段,以中值为枢轴,从各段段首(或段尾)开始选数
//思路解析:假设排序后为a1 a2...an mid b1 b2...bn,则组织为a1 b1 a2 b2...
//此法时间复杂度为O(n),如果没有O(1)的空间复杂度,比较简单,正是这个限制增加了复杂度
class
Solution
{
public
:
void
wiggleSort
(
vector
<
int
>&
nums
)
{
int
m
=
nums
.
size
();
auto
mptr
=
nums
.
begin
()
+
(
m
-
1
)/
2
;
nth_element
(
nums
.
begin
(),
mptr
,
nums
.
end
());
int
median
=
*
mptr
;
int
i
=
1
;
// position for the larger values: start with first odd index
int
j
=
((
m
-
1
)
&
1
)
?
m
-
2
:
m
-
1
;
// position for the smaller values: start with last even index
for
(
int
l
=
0
;
l
<
m
;
++
l
)
{
if
(
nums
[
l
]
>
median
)
{
// fill the large element
if
(
l
<=
i
&&
(
l
&
1
))
continue
;
// skip the elements which are already checked: 1, 3, 5, ..., i
swap
(
nums
[
l
--],
nums
[
i
]);
i
+=
2
;
}
else
if
(
nums
[
l
]
<
median
)
{
// fill the smaller element
if
(
l
>=
j
&&
(
l
&
1
)
==
0
)
continue
;
// skip the elements whcih are checked: j, j + 2, ..., lastEvenIndex
swap
(
nums
[
l
--],
nums
[
j
]);
j
-=
2
;
}
}
}
};
//
方法一:排序后,分成两段,从各段末尾依次取数(可以避免相等数弄在一起)
//
不过此法的时间复杂度为
O(nlogn),空间复杂度为O(n),不满足题意
//
思路解析:假设排序后为
a1 a2...an b1 b2...bn,
则组织为
an bn an-1 bn-1...
class
Solution
{
public
:
void
wiggleSort
(
vector
<
int
>&
a
)
{
int
n
=
a
.
size
();
sort
(
a
.
begin
(),
a
.
end
());
if
(
n
<=
2
)
return
;
//
小于两个元素时,直接退出
vector
<
int
>
temp
=
a
;
int
i
=
0
,
j
=(n-1)/2, k=n-1;
//i
用来遍历
a, j
用来遍历
temp
第一段(从末尾开始),
k
用来遍历第二段。
for
(
i
=
0
;
i
<
n
;
i
++)
{
a
[
i
]
=
(
i
&
1
)?
temp
[
k
--]:
temp
[
j
--];
//
如果i为奇数,取第二段的数(较大),如果为偶数,取第一段的数(较小)
//
注:当
n
为奇数时,两段长度不等,第一段比第二段多
1
,但是上述等式可以保证最后一个数
a[n-1]
选择
temp[0]
}
}
};
/*
//摆动排序,a[0] < a[1] > a[2] < a[3]...
//要得到O(n)时间复杂度,O(1)空间复杂度,可以借鉴wiggle sort I(a[0] <= a[1] >= a[2] <= a[3]...)中的思路
//测试结果表明,对于序列中有多个连续相等数时,此方法不行,因为按照交换策略,相等的数会交换,但是交换后并不会满足
class Solution
{
public:
void wiggleSort(vector& a)
{
int n = a.size();
if(n <= 1) return; //元素个数少于1个时,退出
for(int i = 1; i < n; i++)
{
if((i%2 == 1 && a[i]<=a[i-1]) || (i%2 == 0 && a[i]>=a[i-1]))
{
swap(a[i], a[i-1]);//如果不符合摆动规律则交换
}
}
}
};
*/
Wiggle Sort I
Given an unsorted array nums, reorder it in-place such that
nums[0] <= nums[1] >= nums[2] <= nums[3]....
For example, given nums = [3, 5, 2, 1, 6, 4], one possible answer is [1, 6, 2, 5, 3, 4].
这道题让我们求摆动排序,跟 Wiggle Sort II
相比起来,这道题的条件宽松很多,只因为多了一个等号。由于等号的存在,当数组中有重复数字存在的情况时,也很容易满足题目的要求。这道题我们先来看一种时间复杂度为
O(nlgn)
的方法,
思路是先给数组排个序,然后我们只要每次把第三个数和第二个数调换个位置,第五个数和第四个数调换个位置,以此类推直至数组末尾
,这样我们就能完成摆动排序了,参见代码如下:
//解法一:
// Time Complexity O(nlgn)
class
Solution
{
public
:
void
wiggleSort
(
vector
<
int
>
&
nums
)
{
sort
(
nums
.
begin
(),
nums
.
end
());
if
(
nums
.
size
()
<=
2
)
return
;
for
(
int
i
=
2
;
i
<
nums
.
size
();
i
+=
2
)
{
swap
(
nums
[
i
],
nums
[
i
-
1
]);
}
}
};
这道题还有一种O(n)的解法,根据题目要求的nums[0] <= nums[1] >= nums[2] <= nums[3]....,我
们可以总结出如下规律:
当i为奇数时,nums[i] >= nums[i - 1]
当i为偶数时,nums[i] <= nums[i - 1]
那么我们只要对每个数字,
根据其奇偶性,跟其对应的条件比较,如果不符合就和前面的数交换位置即可
,参见代码如下:
//解法二:
// Time Complexity O(n)
class
Solution
{
public
:
void
wiggleSort
(
vector
<
int
>
&
nums
)
{
if
(
nums
.
size
()
<=
1
)
return
;
for
(
int
i
=
1
;
i
<
nums
.
size
();
++
i
)
{
if
((
i
%
2
==
1
&&
nums
[
i
]
<
nums
[
i
-
1
])
||
(
i
%
2
==
0
&&
nums
[
i
]
>
nums
[
i
-
1
]))
{
swap
(
nums
[
i
],
nums
[
i
-
1
]);
}
}
}
};
来源: http://www.cnblogs.com/grandyang/p/5177285.html
posted @
2019-01-05 20:17 wikiwen 阅读(
...) 评论(
...) 编辑 收藏