LeetCode Top100의 70,72,75 개의 질문

70. 계단 오르기

① 제목 ​​설명
  • 계단을 오르고 있다고 가정합니다. 건물 꼭대기에 도달하려면 n 단계가 필요합니다.
  • 매번 1 ~ 2 걸음 올라갈 수 있습니다. 건물 꼭대기에 오르려면 몇 가지 방법이 필요합니까?
  • 참고 : 주어진 n은 양의 정수입니다.
  • 예 1 :

입력 : 2
출력 : 2
설명 : 건물 꼭대기에 오르는 방법은 두 가지가 있습니다.

  1. 1 차 + 1 차
  2. 2 단계
  • 예 2 :

입력 : 3
출력 : 3
설명 : 건물 꼭대기에 오르는 방법은 세 가지가 있습니다.

  1. 1 차 + 1 차 + 1 차
  2. 1 차 + 2 차
  3. 2 차 + 1 차
② 재귀 솔루션 ( Time Limit Exceeded)
  • 는 n 번째 단계까지 전에, 하나 개 또는 두 단계를 이동으로 인해 시간, N 층 단계 이동을 요구에 대해 재귀 적 사고를 사용하려면, 상기 유지해야 n - 1이전 수준 또는 n - 2무대. 따라서 f (n)을 사용하여 n 단계의 이동을 나타냅니다. 그때,
    f ( n ) = f ( n - 1) + f ( n - 2 )
    f ( 1 ) = 1,f ( 2 ) = 2
  • 마법 같은 것을 발견했습니다. 이것은 피보나치 수열 (Fibonacci 수열)입니다.
  • 폭력적이며 재귀를 사용하여 작성하십시오. 그러나 그것은 37 시로 밝혀졌습니다 Time Limit Exceeded!
  • 시간 복잡도 : 트리 다이어그램, O (2n) O (2 ^ n)O ( 2n )
  • 코드 쇼 :
public int climbStairs(int n) {
    
    
    if (n == 1) {
    
    
        return 1;
    }
    if (n == 2) {
    
    
        return 2;
    }
    return climbStairs(n - 2) + climbStairs(n - 1);
}
③ 재귀 적 최적화
  • 으로 f(4), 예를 들어, 우리는 각각 해결해야 f(3)하고 f(2), 해결 f(3),시에 지점을 해결하기 위해 필요 f(2)하고 f(1)사실, f(2)이미 이전에 해결되었다.
    여기에 사진 설명 삽입
  • 최적화는 memoization기술 이라고하는 재귀를 다시 입력하지 않고 직접 사용할 때 수요를 유지 한 솔루션을 찾는 것 입니다.
  • 이 기술은 이전 재귀 방법의 최적화에도 사용됩니다!
  • 코드 쇼 :
public int climbStairs(int n) {
    
    
    HashMap<Integer, Integer> map = new HashMap<>();
    return climbStairsN(n, map);
}

public int climbStairsN(int n, HashMap<Integer, Integer> map) {
    
    
    if (n == 1) {
    
    
        return 1;
    }
    if (n == 2) {
    
    
        return 2;
    }
    int f1 = 0;
    if (map.containsKey(n - 1)) {
    
    
        f1 = map.get(n - 1);
    } else {
    
    
        f1 = climbStairsN(n - 1, map);
        map.put(n - 1, f1);
    }
    int f2 = 0;
    if (map.containsKey(n - 2)) {
    
    
        f2 = map.get(n - 2);
    } else {
    
    
        f2 = climbStairsN(n - 2, map);
        map.put(n - 2, f2);
    }
    map.put(n, f1 + f2);
    return f1 + f2;
}
④ 어레이 사용
  • f[]피보나치 수열을 저장할 새 배열 만들고 초기화 f[1] = 1, f[2] = 2;한 다음 f[i] = f[i - 1] + f[i - 2].
  • 공간 복잡도는 O (n) O (n) 이지만O ( n ) , 그러나 시간 복잡도는O (n) O (n)O ( n ) 이므로 실행 시간은0ms입니다.
  • 코드 쇼 :
public int climbStairs(int n) {
    
    
    if (n == 1) {
    
    
        return 1;
    }
    if (n == 2) {
    
    
        return 2;
    }
    int[] f = new int[n + 1];
    f[1] = 1;
    f[2] = 2;
    for (int i = 3; i <= n; i++) {
    
    
        f[i] = f[i - 1] + f[i - 2];
    }
    return f[n];
}

72. 거리 수정

② 제목 설명
  • 두 단어를 감안 word1하고 word2계산하는 word1변환 word2사용 작업의 최소 수입니다.
  • 단어에 대해 다음 세 가지 작업을 수행 할 수 있습니다
    . 문자 삽입, 문자
    삭제, 문자
    바꾸기
  • 예 1 :

입력 : word1 = "horse", word2 = "ros"
출력 : 3
설명 :
horse-> rorse ( '
h '를 'r'로 대체 ) rorse-> rose (delete'r ') rose-
> ros (delete' 이자형')

  • 예 2 :

입력 : word1 = "intention", word2 = "execution"
출력 : 5
설명 : intention-> inention (delete't ')
inention-> enention (
replace'i'with'e ') enention-> exention (change'
n '을' x '로 대체) exention-> exection (replace'n'with'c ')
exection-> 실행 ( insert'u ')

② 동적 프로그래밍
  • dp[i][j]문자열 word1[ 0, i )(word1은 0 번째에서 i-1 자) 및 word2[ 0, j - 1)최소 편집 거리의 경우.
  • 상태 전이 방정식 :
    ① 만약 word1[i -1] = word2[j - 1], dp[i][j] = dp[i - 1][j - 1]캐릭터가 변경되지 않았기 때문
    word1[i -1] != word2[j - 1],, dp[i][j] = Math.min(dp[i][j - 1], Math.min(dp[i - 1][j], dp[i - 1][j - 1])) + 1단어 1이 각각 추가, 삭제, 대체되면 문자가 단어 2가됩니다.
  • 초기화 :
    dp[0][0]=0, 수단 모두의 길이가 0이며, 최소 편집 거리가 0 인 것을,
    ②로부터 i = 1시작 dp[i][0] = i,, 삭제 문자에 필요한 단계 의미 에서 빈 word2에 단어 1을,
    ③로부터 j = 1시작 dp[0][j] = j,, 즉, 문자 빈 문자에서 단어 1 변경 word2에 필요한 단계.
public int minDistance(String word1, String word2) {
    
    
    int m = word1.length();
    int n = word2.length();
    int[][] dp = new int[m + 1][n + 1];
    // word1有非空变为空所需要的删除步骤
    for (int i = 1; i <= m; i++) {
    
    
        dp[i][0] = i;
    }
    // word1由空变成 word2所需要的添加的步骤
    for (int j = 1; j <= n; j++) {
    
    
        dp[0][j] = j;
    }
    for (int i = 1; i <= m; i++) {
    
    
        for (int j = 1; j <= n; j++) {
    
    
            // word1的下标i-1.其实表示第i个字符,也就是我们当前要求解的字符
            if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
    
    
                dp[i][j] = dp[i - 1][j - 1];
            } else {
    
    
                // min( add, delete, change)+1
                dp[i][j] = Math.min(dp[i][j - 1], Math.min(dp[i - 1][j], dp[i - 1][j - 1])) + 1;
            }
        }
    }
    return dp[m][n];
}

75. 색상 분류

① 제목 ​​설명
  • 빨강, 흰색 및 파랑을 포함하는 n 개의 요소 배열이 주어지면 동일한 색상의 요소가 인접하고 빨강, 흰색 및 파랑 순서로 정렬되도록 정렬합니다.
  • 이 질문에서는 정수 0, 1, 2를 사용하여 각각 빨간색, 흰색 및 파란색을 나타냅니다.
  • 참고 : 이 문제를 해결하기 위해 코드베이스에서 정렬 기능을 사용할 수 없습니다.
  • 예:

입력 : [2,0,2,1,1,0]
출력 : [0,0,1,1,2,2 ]

  • 많은:

직관적 인 해결책은 분류를 계산하기 위해 2 단계 스캐닝 알고리즘을 사용하는 것입니다.
먼저 요소 수 0, 1, 2를 반복적으로 계산 한 다음 0, 1, 2의 순서로 현재 배열을 다시 씁니다.
일정한 공간만을 사용하는 원 패스 스캐닝 알고리즘을 생각할 수 있습니까?

② 더블 포인터 (자신의 생각)
  • 배열이 정렬 된 후의 0,...,0 1,...,1 2,...,2경우 여야하며 , 각각 0, 1, 2의 숫자 인 세 부분으로 생각할 수 있습니다.
  • 따라서 외부 루프는 총 3 회이며 각 패스에서 모든 0을 첫 번째 세그먼트에, 모두 1을 두 번째 세그먼트에, 모두 세 번째 세그먼트에 넣지 마십시오.
  • 내부 루프는 이중 포인터 start指针사용 하여 삽입 할 번호의 위치를 ​​나타내며 삽입 cur指针할 수있는 번호를 찾기 위해 계속 뒤로 이동합니다.
  • 각 메모리 루프에서 nums[start]i 일 경우 시작점을 업데이트해야하며 시작은 경계를 넘을 수 없습니다. 삽입 할 번호의 위치를 ​​결정한 후 cur start+1삽입 할 수있는 번호를 찾기 위해 배열 처음부터 뒤로 이동합니다.
  • 번호를 삽입 할 수 없으며 cur은 다음 번호를 가리 킵니다. 그렇지 않으면 start와 cur은 동시에 다음 번호를 가리 킵니다.
  • 코드 쇼 :
public void sortColors(int[] nums) {
    
    
    if (nums.length == 0 || nums.length == 1) {
    
    
        return;
    }
    int start = 0;
    for (int i = 0; i < 3; i++) {
    
    
        while (start < nums.length && nums[start] == i) {
    
    
            start++;
        }
        int cur = start + 1;
        while (cur < nums.length) {
    
    // cur向后遍历,直到遍历完数组
            if (nums[cur] == i) {
    
    // 找到了待插入的数字,交换cur和start指向数字
                int temp = nums[start];
                nums[start] = nums[cur];
                nums[cur] = temp;
                start++;  // start+1指向下一个待插入数字的位置
            }
            cur++;
        }
    }
}
③ 0과 1의 수를 세고 0,1,2의 해당 수를 배열에 더합니다.
  • 코드 쇼 :
public void sortColors(int[] nums) {
    
    
    if (nums.length == 0 || nums.length == 1) {
    
    
        return;
    }
    int zero_count = 0;
    int one_count = 0;
    for (int i = 0; i < nums.length; i++) {
    
    
        if (nums[i] == 0) {
    
    
            zero_count++;
        }
        if (nums[i] == 1) {
    
    
            one_count++;
        }
    }
    // 将对应位置的数字改为对应数目的0,1,2
    for (int i = 0; i < nums.length; i++) {
    
    
        if (zero_count > 0) {
    
    
            nums[i] = 0;
            zero_count--;
        } else if (one_count > 0) {
    
    // 只有当0的个数加满后,才能添加1
            nums[i] = 1;
            one_count--;
        } else {
    
    
            nums[i] = 2;
        }
    }
}

추천

출처blog.csdn.net/u014454538/article/details/90665738