下载APP

求最长递增子序列的四种解法


theme: channing-cyan highlight: arduino-light

求最长递增子序列的四种解法

动态规划 复杂度 O(n^2)

/**
 * 动态规划 复杂度 O(n^2)
 * @param nums
 * @return
 */
public static int lengthOfLIS(int[] nums) {
    int ans = 1;
    int[] dp = new int[nums.length];
    Arrays.fill(dp, 1);
    for (int j = 0; j < nums.length; j++) {
        for (int i = 0; i < j; i++) {
            if (nums[j] > nums[i]) {
                dp[j] = Math.max(dp[j], dp[i] + 1);
                ans = Math.max(ans, dp[j]);
            }
        }
    }
    return ans;
}

动态规划 + 二分优化,复杂度 O(nlogn)

/**
 * 动态规划 + 二分优化,复杂度 O(nlogn)
 * @param nums
 * @return
 */
public static int lengthOfLIS(int[] nums) {
    int cnt = 0;
    int[] sta = new int[nums.length];
    sta[cnt] = nums[0];
    for (int i = 1; i < nums.length; i++) {
        if (nums[i] > sta[cnt]) {
            sta[++cnt] = nums[i];
            continue;
        }
        // 严格递增一定用lowBound,否则可能会出现重复,eg: [4, 10, 4]
        int pos = lowBound(sta, cnt, nums[i]);
        if (pos == -1) {
            continue;
        }
        sta[pos] = nums[i];
    }
    return cnt + 1;
}

private static int upperBound(int[] sta, int cnt, int num) {
    int l = 0, r = cnt, pos = -1;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (sta[mid] > num) {
            pos = mid;
            r = mid - 1;
        } else {
            l = mid + 1;
        }
    }
    return pos;
}

private static int lowBound(int[] nums, int cnt, int val) {
    int l = 0, r = cnt, pos = -1;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (nums[mid] >= val) {
            r = mid - 1;
            pos = mid;
        } else {
            l = mid + 1;
        }
    }
    return pos;
}

动态规划 + 树状数组优化 复杂度 O(nlogn)

/**
 * 动态规划 + 树状数组优化 复杂度 O(nlogn)
 * @param nums
 * @return
 */
public static int lengthOfLIS(int[] nums) {
    // 离散化
    int[] spread = Arrays.copyOf(nums, nums.length);
    Arrays.sort(spread);
    spread = Arrays.stream(spread).distinct().toArray();
    Map<Integer, Integer> orderMap = new HashMap<>();
    for (int i = 0; i < spread.length; i++) {
        orderMap.put(spread[i], i + 1);
    }
    int ans = 1;
    int[] c = new int[nums.length + 1];
    for (int num : nums) {
        // 查询[0, j - 1]区间最大f[i]
        int mx = query_max(orderMap.get(num) - 1, c);
        ans = Math.max(ans, mx + 1);
        // 更新 f[j] = f[i] + 1
        update_num(orderMap.get(num), mx + 1, nums.length + 1, c);
    }
    return ans;
}

private static void update_num(int num, int val, int n, int[] c) {
    for (int i = num; i < n; i += lowBit(i)) {
        c[i] = Math.max(c[i], val);
    }
}

private static int query_max(int num, int[] c) {
    int ans = 0;
    for (int i = num; i > 0; i -= lowBit(i)) {
        ans = Math.max(ans, c[i]);
    }
    return ans;
}

动态规划 + 权值线断树优化

/**
 * 动态规划 + 权值线断树优化
 * @param nums
 * @return
 */
public static int lengthOfLIS(int[] nums) {
    // 离散化
    int[] spread = Arrays.copyOf(nums, nums.length);
    Arrays.sort(spread);
    spread = Arrays.stream(spread).distinct().toArray();
    Map<Integer, Integer> orderMap = new HashMap<>();
    for (int i = 0; i < spread.length; i++) {
        orderMap.put(spread[i], i + 1);
    }
    int ans = 1;
    int[] maxVal = new int[4 * nums.length + 1];
    for (int num : nums) {
        if (orderMap.get(num) == 1) {
            tree_update_num(orderMap.get(num), 1, 1, spread.length, 1, maxVal);
            continue;
        }
        int mx = tree_query_max(1, orderMap.get(num) - 1, 1, spread.length, 1, maxVal);
        ans = Math.max(ans, mx + 1);
        tree_update_num(orderMap.get(num), mx + 1, 1, spread.length, 1, maxVal);
    }
    return ans;
}

private static void tree_update_num(int pos, int val, int l, int r, int k, int[] maxVal) {
    if (l == r) {
        maxVal[k] = val;
        return;
    }
    int mid = (l + r) >> 1;
    if (pos <= mid) {
        tree_update_num(pos, val, l, mid, k << 1, maxVal);
    } else {
        tree_update_num(pos, val, mid + 1, r, k << 1 | 1, maxVal);
    }
    maxVal[k] = Math.max(maxVal[k << 1], maxVal[k << 1 | 1]);
}

private static int tree_query_max(int ql, int qr, int l, int r, int k, int[] maxVal) {
    if (l >= ql && r <= qr) {
        return maxVal[k];
    }
    int mid = (l + r) >> 1, ans = 0;
    if (ql <= mid) {
        ans = Math.max(ans, tree_query_max(ql, qr, l, mid, k << 1, maxVal));
    }
    if (qr > mid) {
        ans = Math.max(ans, tree_query_max(ql, qr, mid + 1, r, k << 1 | 1, maxVal));
    }
    return ans;
}
在线举报