A node is a local maxima if the current node has a value strictly greater than the previous node and the next node.
A node is a local minima if the current node has a value strictly smaller than the previous node and the next node.
Note that a node can only be a local maxima/minima if there exists both a previous node and a next node.
Given a linked list head, return an array of length 2 containing [minDistance, maxDistance] where minDistance is the minimum distance between any two distinct critical points and maxDistance is the maximum distance between any two distinct critical points. If there are fewer than two critical points, return [-1, -1].
Example 1:
Input: head = [3,1] Output: [-1,-1] Explanation: There are no critical points in [3,1].
Example 2:
Input: head = [5,3,1,2,5,1,2] Output: [1,3] Explanation: There are three critical points: - [5,3,1,2,5,1,2]: The third node is a local minima because 1 is less than 3 and 2. - [5,3,1,2,5,1,2]: The fifth node is a local maxima because 5 is greater than 2 and 1. - [5,3,1,2,5,1,2]: The sixth node is a local minima because 1 is less than 5 and 2. The minimum distance is between the fifth and the sixth node. minDistance = 6 - 5 = 1. The maximum distance is between the third and the sixth node. maxDistance = 6 - 3 = 3.
Example 3:
Input: head = [1,3,2,2,3,2,2,2,7] Output: [3,3] Explanation: There are two critical points: - [1,3,2,2,3,2,2,2,7]: The second node is a local maxima because 3 is greater than 1 and 2. - [1,3,2,2,3,2,2,2,7]: The fifth node is a local maxima because 3 is greater than 2 and 2. Both the minimum and maximum distances are between the second and the fifth node. Thus, minDistance and maxDistance is 5 - 2 = 3. Note that the last node is not considered a local maxima because it does not have a next node.
Constraints:
[2, 105].1 <= Node.val <= 105연결 리스트
다음은 주어진 알고리즘 문제에 대한 풀이 설명입니다.
이 문제는 단일 연결 리스트(Singly Linked List)에서 "임계점(Critical Point)"을 찾아, 임계점들 사이의 최소 및 최대 거리를 계산하는 것을 요구합니다.
임계점의 정의:
거리의 정의: 두 임계점 사이의 거리는 그들의 0-기반 인덱스(위치) 차이로 정의됩니다.
요구사항:
[minDistance, maxDistance] 형태의 배열을 반환합니다.minDistance: 두 어떤 서로 다른 임계점 사이의 최소 거리.maxDistance: 두 어떤 서로 다른 임계점 사이의 최대 거리 (이는 첫 번째 임계점과 마지막 임계점 사이의 거리가 됩니다).[-1, -1]을 반환합니다.입력: 연결 리스트의 head 노드.
제약 조건: 리스트의 노드 수는 2개 이상 10^5개 이하. 노드 값은 1 이상 10^5 이하.
문제를 해결하기 위해 연결 리스트를 한 번만 순회하는 접근 방식을 사용합니다. 각 노드를 방문하면서 임계점인지 확인하고, 임계점이라면 그 노드의 인덱스(위치)를 기록합니다.
min_a 변수와 tmp (가장 최근 임계점 인덱스) 변수를 사용합니다.result)를 유지합니다. 모든 순회가 끝난 후, 이 리스트의 첫 번째 임계점과 마지막 임계점의 인덱스 차이가 최대 거리가 됩니다.result 리스트에 2개 미만의 임계점이 저장되었다면, [-1, -1]을 반환합니다.이 방법은 연결 리스트를 한 번만 순회하므로 효율적이며, 추가적인 정렬이나 복잡한 자료구조 없이 문제를 해결할 수 있습니다.
주어진 코드는 다음 단계로 나누어 설명할 수 있습니다.
bb_num, b_num 초기화: bb_num은 '이전의 이전 노드'의 값을, b_num은 '이전 노드'의 값을 저장합니다. head.val이 '현재 노드'의 값이 됩니다. 이 세 변수를 통해 임계점 판별에 필요한 세 개의 연속된 노드 값을 유지합니다. 초기에는 None으로 설정됩니다.result 리스트 초기화: 발견된 모든 임계점의 인덱스를 저장할 빈 리스트입니다.cnt 초기화: 현재 순회 중인 노드의 0-기반 인덱스를 추적하는 카운터입니다. 0으로 시작합니다.min_a 초기화: 최소 거리를 저장할 변수로, float("inf") (무한대)로 초기화하여 어떤 실제 거리 값도 이보다 작게 만듭니다.tmp 초기화: 가장 최근에 발견된 임계점의 인덱스를 저장할 변수입니다. 초기에는 None입니다.while head: 루프 안에서, bb_num이 None일 때는 head.val을 bb_num에 할당하고, b_num이 None일 때는 head.val을 b_num에 할당합니다. 이 두 노드는 임계점이 될 수 없으므로, 값을 저장하고 다음 노드로 넘어갑니다. 이 단계를 통해 임계점 검사를 위한 최소 세 개의 노드 값을 확보합니다.else 블록은 bb_num과 b_num에 유효한 값이 할당된, 즉 세 번째 노드부터 실행됩니다.if (b_num > bb_num and b_num > head.val) or (b_num < bb_num and b_num < head.val):
b_num (이전 노드)이 bb_num (이전의 이전 노드)과 head.val (현재 노드) 사이에서 지역 최대값 또는 지역 최소값인지 확인합니다.b_num의 노드가 임계점이라는 것이고, 이 노드의 인덱스는 cnt - 1입니다.if not tmp:: 만약 현재 발견된 임계점이 첫 번째 임계점이라면, 그 인덱스(cnt - 1)를 tmp에 저장합니다.else:: 이미 이전에 임계점이 발견된 경우, 현재 임계점(cnt - 1)과 이전 임계점(tmp) 사이의 거리를 계산 ((cnt - 1) - tmp)하여 min_a를 업데이트합니다. 이후 tmp를 현재 임계점의 인덱스(cnt - 1)로 업데이트합니다.result.append(cnt - 1)을 통해 현재 발견된 임계점의 인덱스 (cnt - 1)를 result 리스트에 추가합니다.bb_num = b_num: 이전 노드의 값이 '이전의 이전 노드'의 값으로 옮겨집니다.b_num = head.val: 현재 노드의 값이 '이전 노드'의 값으로 옮겨집니다.head = head.next: head 포인터를 다음 노드로 이동시킵니다.cnt += 1: 노드 인덱스 카운터를 증가시킵니다.while 루프가 끝나면 모든 노드를 순회하고 임계점들을 처리한 상태입니다.if len(result) < 2:
result 리스트에 임계점이 2개 미만으로 저장되어 있다면, 문제의 요구사항에 따라 [-1, -1]을 반환합니다.return [min_a, result[-1]-result[0]]
min_a는 위에서 계산된 최소 거리를 나타냅니다.result[-1] - result[0]는 result 리스트의 마지막 임계점 인덱스에서 첫 번째 임계점 인덱스를 뺀 값으로, 이는 연결 리스트 내의 최대 거리가 됩니다 (왜냐하면 result에 저장된 인덱스들은 항상 오름차순이기 때문입니다).시간 복잡도: O(N)
공간 복잡도: O(N)
result 리스트는 발견된 모든 임계점의 인덱스를 저장합니다. 최악의 경우, 연결 리스트의 절반에 가까운 노드들이 임계점이 될 수 있습니다 (예: [1, 5, 1, 5, 1, 5, ...]).result 리스트의 크기는 O(N)이 될 수 있습니다.bb_num, b_num, cnt, min_a, tmp 등의 다른 변수들은 상수 공간(O(1))을 사용합니다.bb_num, b_num, head.val). 이를 통해 연결 리스트를 한 번만 순회하면서 효율적으로 임계점 조건을 확인할 수 있습니다.cnt 변수를 사용하여 현재 head가 가리키는 노드의 인덱스를 유지하고, 임계점으로 판별된 b_num 노드의 실제 인덱스(cnt - 1)를 정확히 기록합니다.min_a를 업데이트하는 '온더플라이(on-the-fly)' 방식으로 O(1) 시간에 최소 거리를 찾습니다.result 리스트에 순서대로 저장한 후, 마지막 임계점 인덱스에서 첫 번째 임계점 인덱스를 빼는 방식으로 O(1) 시간에 최대 거리를 계산합니다. 이 방식은 인덱스들이 이미 정렬되어 있기 때문에 가능합니다.# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def nodesBetweenCriticalPoints(self, head: Optional[ListNode]) -> List[int]:
bb_num = None
b_num = None
result = []
cnt = 0
min_a = float("inf")
tmp = None
while head:
if not bb_num:
bb_num = head.val
elif not b_num:
b_num = head.val
else:
if (b_num > bb_num and b_num > head.val) or (b_num < bb_num and b_num < head.val):
if not tmp:
tmp = cnt
else:
min_a = min(min_a, cnt-tmp)
tmp = cnt
result.append(cnt)
bb_num = b_num
b_num = head.val
head = head.next
cnt += 1
if len(result) < 2:
return [-1,-1]
return [min_a, result[-1]-result[0]]