동적 기획 과 몰 투표 법
위 키 피 디 아 는 동적 계획 (Dynamic programming · DP 로 약칭) 에 대해 수학, 관리 과학, 컴퓨터 과학, 경제학, 생물 정보 학 에서 사용 하 는 것 으로, 원 문 제 를 상대 적 으로 간단 한 하위 문제 로 분해 하 는 방식 으로 복잡 한 문 제 를 푸 는 방법 을 정의 한다.
피 보 나치 수열
피 보 나치 수열 은 원 문 제 를 상대 적 으로 간단 한 서브 문제 로 분해 하 는 전형 적 인 방식 으로 복잡 한 문 제 를 해결 할 수 있 는 예 이다.다음은 피 보 나치 수열 의 수학 적 정의 이다.
이 수학 정의 에 따 르 면 우 리 는 재 귀적 인 방식 으로 이 알고리즘 을 쉽게 실현 할 수 있다.
package main
import (
"fmt"
"time"
)
func fib(n int) int {
if n <= 1 {
return n
}
return fib(n-1) + fib(n-2)
}
func main() {
start := time.Now().Unix()
fib(45)
end := time.Now().Unix()
fmt.Println(end-start)
}
위의 코드 는 우리 가 구 하 는 것 은 F (45) 이다. 코드 는 매우 간단 하지만 계산 시간 이 6 초 정도 되 고 효율 이 매우 낮다. 다음은 방금 코드 에 따라 그 려 진 F (5) 의 트 리 그림 이다. 그림 에서 알 수 있 듯 이 F (3) 는 2 번 계산 하고 F (2) 는 3 번 계산 하 며 F (1) 는 4 번 계산 하고 중복 계산 이 많이 발생 했다. 이것 도 효율 이 낮은 원인 이다.최적화 해 야 할 사고방식 은 이런 불필요 한 중복 계산 을 없 애 는 것 이다.이제 우 리 는 모든 하위 문제 의 계산 결 과 를 저장 합 니 다. 같은 하위 문제 에 다시 부 딪 혔 을 때 이전에 저 장 된 결과 에서 직접 값 을 얻 을 수 있 으 니 다시 계산 하지 않 아 도 됩 니 다.예 를 들 어 계산 F (2) 를 처음 만 났 을 때 하나의 사전 으로 F (2) 의 계산 결 과 를 저장 할 수 있 습 니 다. 계산 F (2) 를 다시 만 났 을 때 사전 에서 직접 값 을 얻 을 수 있 습 니 다. 개 조 된 코드 는 다음 과 같 습 니 다.
package main
import (
"fmt"
"time"
)
var m = map[int]int{0:0, 1:1}
func fib(n int) int {
if v, ok :=m[n]; ok {
return v
}
m[n-1],m[n-2] =fib(n-1),fib(n-2)
return m[n-1]+m[n-2]
}
func main() {
start := time.Now().UnixNano()
fib(45)
end := time.Now().UnixNano()
fmt.Println(end-start)
}
개 조 를 거 쳐 F (45) 를 계산 하 는 것 은 1 초도 안 된다.일단 정자 문제 에 대한 해답 이 계산 되면 다음 에 같은 하위 문제 가 해 제 될 때 직접 표를 찾 는 것 도 동적 기획 의 중요 한 내용 이다.
그래서 동태 계획 의 두 가지 가장 중요 한 점 은:
4. 567917. 복잡 한 문 제 를 몇 개의 키 문제 로 나 누 었 다
4. 567917. 모든 하위 문제 의 결 과 를 저장 하여 모든 하위 문 제 를 한 번 만 해결 하도록 한다
House Robber
다음은 LeetCode 의 이전 House Robber 라 는 제목 을 동적 기획 방법 으로 해결 하 는 것 입 니 다.
당신 은 전문 적 인 도둑 으로 길 을 따라 있 는 집 을 훔 칠 계획 입 니 다.모든 방 안에 일정한 현금 이 숨겨 져 있 는데 도 난 에 영향 을 주 는 유일한 제약 요 소 는 바로 인접 한 집 이 서로 연 결 된 도 난 방지 시스템 을 설치 하 는 것 이다. 만약 에 인접 한 집 두 칸 이 같은 밤 에 도둑 에 게 침입 하면 시스템 은 자동 으로 경찰 에 신고 할 것 이다.
각 집의 보관 금액 을 대표 하 는 비 마이너스 정수 그룹 을 지정 하여 경보 장 치 를 건 드 리 지 않 은 상태 에서 훔 칠 수 있 는 최고 금액 을 계산한다.
현재 각 주택 이 보관 하고 있 는 금액 이 각각 2, 7, 9, 3, 1 이 라 고 가정 하여 최대 훔 칠 수 있 는 금액 을 구한다.
우 리 는 P (n) 로 총 n 칸 짜 리 집 이 있 을 때 훔 칠 수 있 는 최대 금액 을 표시 하고 r (n) 로 n 번 째 집에 보관 할 수 있 는 금액 을 표시 합 니 다.n 이 1 일 때 P (1) = r (1), n 이 2 일 때 P (2) = Max (r (1), r (2).제목 은 인접 한 방 두 칸 을 약탈 할 수 없 도록 요구 하기 때문에 n 칸 이 있 을 때 P (n) = Max (P (n - 2) + r (n), P (n - 1).방정식 으로 표시 하면:
P(1)=r(1)
P(2)=Max(r(1), r(2))
P(n)=Max(P(n-2)+r(n), P(n-1))
그래서 이 문 제 는 몇 개의 키 문제 로 분해 되 었 고 다음은 코드 가 실현 되 었 다.
package main
import "fmt"
var m = map[int]int{}
func rob(arr []int) int {
l := len(arr)
if l <= 0 {
return 0
}
if v,ok:=m[l-1];ok{
return v
}
if l == 1 {
m[0]=arr[0]
return arr[0]
}
if l == 2 {
if arr[0] >= arr[1] {
m[1]=arr[0]
return arr[0]
} else {
m[1]=arr[1]
return arr[1]
}
}
a, b:= rob(arr[:l-2])+arr[l-1],rob(arr[:l-1])
if a>=b{
m[l-1]=a
} else {
m[l-1]=b
}
return m[l-1]
}
func main() {
arr := []int{2,7,9,3,1}
m[0]=arr[0]
ret :=rob(arr)
fmt.Println(ret)
}
위의 코드 는 바로 우리 가 방정식 에 따라 머리 없 이 쓴 알고리즘 에 따라 최대 금액 을 훔 치 는 목적 을 달성 한 것 이다. 그러나 사실은 최적화 공간 이 있다. 우 리 는 P (n) 를 계산 하려 면 예전 의 P (n - 2) 와 P (n - 1) 만 기억 하면 된다. 그러나 우 리 는 사실 P (1), P (2),..., P (n - 2) 를 모두 기억 하고 메모리 낭 비 를 가 져 왔 다.이 문제 가 발생 한 이 유 는 우리 가 P (n) 를 풀 때 P (n - 1), P (n - 2),..., P (1) 는 위 에서 아래로 구 해 지 는 방식 이기 때 문 입 니 다. 아래 에서 위로 구 해 지 는 방식 으로 바 꾸 면 다음 과 같은 코드 를 쓸 수 있 습 니 다.
package main
import "fmt"
func rob(arr []int) int {
pre1, pre2 := 0, 0
for _,v := range arr {
if pre2+v >= pre1 {
pre1,pre2 = pre2+v,pre1
} else {
pre1,pre2= pre1,pre1
}
}
return pre1
}
func main() {
arr := []int{2,7,9,3,1}
ret :=rob(arr)
fmt.Println(ret)
}
위의 변 수 는 pre 1 과 pre 2 는 각각 P (n - 1) 와 P (n - 2) 를 나타 내 는데 이렇게 하면 아래 에서 위로 결 과 를 구 할 수 있 고 위 에서 아래로 하 는 것 보다 메모 리 를 절약 할 수 있다.
그래서 동태 계획 이 기억 해 야 할 몇 가지 관건 은 복잡 한 문 제 를 몇 개의 키 문제 로 나 누고 서브 문제 의 결 과 를 기억 하 며 위 에서 아래로, 아래 에서 위로 나 누 는 것 이다.
몰 투표 법
만약 10 명 이 투표 에 참여 한다 면, 어떤 사람 은 A 에 게, 어떤 사람 은 B 에 게, 어떤 사람 은 C 에 게 투표 할 것 이다. 우리 가 A, B, C 가 누가 가장 많은 표를 얻 었 는 지 찾 으 려 고 할 때, 우 리 는 두 개의 서로 다른 투 표를 한 쌍 으로 삭제 할 수 있다. 더 이상 삭제 할 수 없 을 때 까지 그 결과 에 남 은 투표 가 가장 많은 표를 얻 은 것 이다.예 를 들 어 상기 10 명의 투표 상황 은 [A, B, C, C, B, A, A, B, A] 이 고 다음은 삭제 하 는 과정 이다.
[A,B,C,C,B,A,A,A,B,A]==>[C,C,B,A,A,A,B,A] //A,B
//
[C,C,B,A,A,A,B,A]==>[C,A,A,A,B,A] //C,C ,
// C,B
[C,A,A,A,B,A]==>[A,A,B,A]
[A,A,B,A]==>[A,A]
끊임없이 서로 다른 투 표를 한 쌍 으로 삭제 함으로써 투표 결과 마지막 에 [A, A] 만 남 았 기 때문에 A 가 가장 많은 표를 얻 었 다.몰 투표 법의 핵심 은 서열 에 있 는 두 개의 서로 다른 요 소 를 상쇄 하거나 삭제 하 는 것 이다. 서열 마지막 에 하나의 요소 나 여러 개의 똑 같은 요 소 를 남 긴 다 면 이 요 소 는 가장 많이 나타 난 요소 이다.
Majority Element
구 중 수 는 바로 몰 투표 법의 전형 적 인 운용 장면 이다. 예 를 들 어 다음 과 같은 알고리즘 문제 가 있다.
n 크기 의 배열 을 지정 하여 그 중의 중 수 를 찾 습 니 다.중 수 는 배열 에서 n / 2 이상 나타 나 는 요 소 를 말한다.주어진 배열 [2, 2, 1, 1, 1, 2, 2, 4, 5, 2, 3, 2, 2] 그 중 수 를 찾 아 라.
구현 코드 는 다음 과 같 습 니 다:
package main
import "fmt"
func main() {
arr := []int{2,2,1,1,1,2,2,4,5,2,3,2,2}
maj, count := arr[0], 1
for i:=1;i
코드 에서 먼저 배열 의 첫 번 째 요 소 는 중수 라 고 가정 하고 하나의 변수 count 로 이 중수 가 나타 난 횟수 를 기록 합 니 다. 교 체 된 숫자 가 이 중수 와 같 을 때 count 는 1 을 추가 하고 다 를 때 상쇄 작업 을 합 니 다. 즉, count 가 1 을 줄 이면 count 가 0 일 때 교체 되 는 수 를 새로운 중수 로 설정 하고 count 를 1 로 설정 합 니 다.
이상 은 몰 투표 법의 원리 와 응용 이다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
124. 두 갈래 나무의 최대 경로와 leetcode비공 두 갈래 트리를 지정하고 최대 경로와 를 되돌려줍니다. 본고에서 경로는 나무의 임의의 노드에서 출발하여 임의의 노드에 도달하는 서열로 정의되었다.이 경로는 루트 노드를 거치지 않고 하나 이상의 노드를 포함합니다...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.