LIS 最长递增子序列 三种求解方式
1 dp
2 二分
3 index tree
题目描述
给出一个列表如[[6,7,],[5,4],[3,2]],表示木块的长和宽,当木块的长和宽不大于另个木块的长和宽时,就可以放在上面,此外数组还可以左右翻转。求最多能搭多少层。
输入描述
一个二维数组,里面是每个积木的长和宽,可以左右翻转。
输出描述
最多能搭多少层。
样例
输入
[[5,4],[6,3],[6,7],[6,6],[4,6]]
1
输出
4
————————————————
package com.company;
import java.io.FileInputStream;
import java.util.*;
// 叠积木
public class Solution32 {
static int[] lisTree;
public static void main(String[] args) throws Exception {
System.setIn(new FileInputStream("D:/data.txt"));
Scanner sc = new Scanner(System.in);
String[] split = sc.nextLine().split("],");
ArrayList<int[]> arr = new ArrayList<>();
for (int i = 0; i < split.length; i++) {
String s = split[i].replaceAll("\\[", "").replaceAll("]", "");
String[] strings = s.split(",");
int a = Integer.valueOf(strings[0]);
int b = Integer.valueOf(strings[1]);
arr.add(new int[]{a>b ? a : b, a <= b ? a : b}); // 长的按照长进行组合
}
Collections.sort(arr, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
if(o1[0] == o2[0]) return o1[1] - o2[1];
return o1[0] - o2[0];
}
});
int len = arr.size();
// method1 dp
int ans = 0;
int[] dp = new int[len];
Arrays.fill(dp, 1);
for (int i = 0; i < len; i++) {
int[] cur = arr.get(i);
for (int j = 0; j < i; j++) {
int[] pre = arr.get(j);
if(cur[1] >= pre[1]) {
dp[i] = dp[j] + 1;
}
}
if(dp[i] > ans) ans = dp[i];
}
System.out.println(ans);
ans = 0;
// method2 二分法
dp[ans++] = arr.get(0)[1];
for (int i = 1; i < len; i++) {
int[] cur = arr.get(i);
if(cur[1] >= dp[ans - 1]) {
dp[ans++] = cur[1];
} else {
int left = 0, right = ans;
while(left < right) {
int mid = left + (right - left) / 2;
int[] c = arr.get(mid);
if(cur[i] > c[1]) {
left = mid + 1;
}
if(cur[1] <= c[1]) {
right = mid;
}
}
dp[left] = cur[1];
}
}
System.out.println(ans);
// method3 indexTree
// 1. 计算构造树需要的的len
int size = 1;
while (size < len) {
size += size;
}
lisTree = new int[size * 2];
// 2. 构造进行操作计算的数据
Node[] data = new Node[len];
for (int i = 0; i < len; i++) {
int[] ints = arr.get(i);
data[i] = new Node(i, ints[1]);
}
// 3. 对索引树进行排序
Arrays.sort(data, new Comparator<Node>() {
@Override
public int compare(Node o1, Node o2) {
if(o1.val == o2.val) {
return o1.idx - o2.idx; // 求不递增 索引小在前
}
return o1.val - o2.val;
}
});
// 4. 定义 query 和 update 方法
// 5. 查询和更新索引树
for (int i = 0; i < len; i++) {
int val = query(size, data[i].idx + size);
update(data[i].idx + size, val + 1);
}
System.out.println(query(size, size * 2 - 1));
}
private static int query(int s, int e) {
int ret = 0;
while (s <= e) {
if(s % 2 == 1) ret = Math.max(ret, lisTree[s]);
if(e % 2 == 0) ret = Math.max(ret, lisTree[e]);
s = (s+1) >> 1;
e = (e-1) >> 1;
}
return ret;
}
private static void update(int idx, int val) {
while (idx > 0) {
lisTree[idx] = val;
idx >>= 1;
}
}
static class Node {
int idx;
int val;
public Node(int idx, int val) {
this.idx = idx;
this.val = val;
}
}
}

浙公网安备 33010602011771号