Next Permutation
https://leetcode.com/problems/next-permutation/description/
풀기 전
몇 가지 observation을 해보면 쉽게 풀 수 있다.
Observation 1 : 오른쪽 파트가 내림차순 정렬된 상태가 되면 그 다음차례에 앞 숫자가 바뀐다.
Example
2 3 1 → 오른쪽 [3 1]이 내림차순 정렬된 상태
3 1 2 → 그 앞 숫자였던 2가 3으로 바뀌었다.
Observation 2 : Observation 1에서 앞 숫자가 바뀔 때는 오른쪽 숫자 중에 그 숫자 바로 다음으로 큰 숫자로 바뀐다.
Example
2 3 1 → 오른쪽 [3 1]이 내림차순 정렬된 상태, 다음에 그 앞 숫자인 2가 바뀌어야 된다.
이때 오른쪽 [3 1] 중에 2 다음으로 큰 숫자는 3이므로 3으로 바뀌어야된다.
3 1 2 → 그 앞 숫자였던 2가 3으로 바뀌었다.
Observation 3 : Observation 1에서 앞 숫자가 바뀐 뒤에 오른쪽 파트는 오름차순 정렬된다.
2 3 1 → 오른쪽 [3 1]이 내림차순 정렬된 상태
3 1 2 → 3 오른쪽 파트 [1 2]는 오름차순 정렬된 상태이다.
Observation 4 : 모든 숫자가 내림차순 정렬되어 있으면 다시 처음으로 돌아가 모든 숫자가 오름차순 정렬된 상태가 된다.
[4 3 2 1] → 모든 숫자가 내림차순
[1 2 3 4] → 모든 숫자가 오름차순 정렬된 상태가 그 next permutation이다.
코드 설명
여러 가지 버전으로 짜봤다.
1. 최대한의 효율 추구
class Solution:
def nextPermutation(self, nums: List[int]) -> None:
# 오른쪽에서 내림차순 정렬된 파트 찾기
i = len(nums) - 1
while i > 0:
if nums[i] > nums[i - 1]:
break
i -= 1
# 전부 다 내림차순이면 그냥 뒤집고 리턴
if i == 0:
for i in range(len(nums) // 2):
tmp = nums[i]
nums[i] = nums[-i - 1]
nums[-i - 1] = tmp
return
# 이진탐색
low = i
high = len(nums) - 1
while low <= high:
mid = (low + high) // 2
if nums[mid] > nums[i - 1] and (mid == len(nums) - 1 or nums[mid + 1] <= nums[i - 1]):
j = mid
break
elif nums[mid] > nums[i - 1]:
low = mid + 1
else:
high = mid - 1
# 스왑
tmp = nums[i - 1]
nums[i - 1] = nums[j]
nums[j] = tmp
# 오른쪽 파트 오름차순으로
for k in range(i, (i + len(nums)) // 2):
nums[k], nums[len(nums)-(k-i)-1] = nums[len(nums)-(k-i)-1], nums[k]
for문을 가급적이면 덜 쓰고
튜플을 이용한 스왑이 아닌 클래식한 방법으로 스왑을 진행한다.
그리고 정렬된 부분에서 왼쪽 숫자보다 큰 숫자를 찾을 때 이진탐색을 이용한다.
오른쪽 정렬된부분이 길면 길수록 효율적인데
문제 테스트케이스가 그런 케이스가 많진 않은지 이진탐색 적용하고 속도가 확 느려졌다.
2.가장 빠른 속도가 나왔던 버전
class Solution:
def nextPermutation(self, nums: List[int]) -> None:
# 오른쪽 내림차순파트 찾기
i = len(nums) - 1
while i > 0:
if nums[i] > nums[i - 1]:
break
i -= 1
# 전부다 내림차순이면 뒤집고 리턴
if i == 0:
nums.reverse()
return
# 왼쪽 숫자보다 큰 숫자 찾고 스왑
j = len(nums) - 1
while nums[j] <= nums[i - 1] and j > i:
j -= 1
nums[i - 1], nums[j] = nums[j], nums[i - 1]
# 오른쪽 파트 오름차순으로 정렬
for k in range(i, (i + len(nums)) // 2):
nums[k], nums[len(nums)-(k-i)-1] = nums[len(nums)-(k-i)-1], nums[k]
3. 극한의 간결함
class Solution:
def nextPermutation(self, nums: List[int]) -> None:
for i in range(len(nums) - 1, 0, -1):
if nums[i] > nums[i - 1]: break
else: return nums.reverse()
for j in range(len(nums) - 1, i - 1, -1):
if nums[j] > nums[i - 1]: break
nums[i - 1], nums[j] = nums[j], nums[i - 1]
nums[i:] = nums[i:][::-1]
분석
시간복잡도 O(N)
공간복잡도 O(1)
'코딩 테스트 및 알고리즘 > leetcode for google' 카테고리의 다른 글
| leetcode easy : Excel Sheet Column Title (0) | 2023.01.12 |
|---|---|
| leetcode easy : Intersection of Two Linked List (0) | 2023.01.10 |
| leetcode hard : Shortest Path Visiting All Nodes (0) | 2023.01.02 |
| leetcode easy : Backspace String Compare (0) | 2023.01.02 |
| leetcode hard : Median Of Two Sorted Arrays (1) | 2022.12.30 |