POJ3061 Subsequence
内容来源于挑战程序设计竞赛
假设从 as开始的总和最初大于target的连续子序列表示为
as + as+1 + …… + at-1 > target
as+1 + as+2 + at-2 < as + as+1 + at-2 < target
而从 as+1开始的总和最初大于target的连续子序列如果是
as+1 + …… + at’-1 > target
则必有 t’ >= t
尺取法:可以用一对数不断维护数组里面的一个区间,反复的推进区间的开头和末尾,来求取满足条件的最小区间的方法
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
/**
* @author wangshaoyu
*/
public class POJ3061Subsequence {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StreamTokenizer st = new StreamTokenizer(br);
static int nextInt() throws IOException {
st.nextToken();
return (int) st.nval;
}
public static void main(String[] args) throws IOException {
int t = nextInt();
while (t-- > 0) {
int n = nextInt();
int target = nextInt();
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = nextInt();
}
int start = 0; // 区间左端点
int end = 0; // 区间右端点
int sum = 0; // 当前区间和
int ans = n + 1;
while (true) {
while (end < n && sum < target) {
sum += nums[end];
end++;
}
// 当 sum 加到了最后一个元素还是小于 target,就可以退出循环了
if (sum < target) {
break;
}
// 此时 end 是指向当前区间的下一个元素,[start, end) 左闭右开区间
ans = Math.min(ans, end - start);
sum -= nums[start];
start++;
}
if (ans == n + 1) {
System.out.println(0);
}
else {
System.out.println(ans);
}
}
}
}
POJ 3320 Jessica’s Reading Problem
在poj上一直编译出错,试了几个样例还行,不知道有没有错。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.HashMap;
import java.util.HashSet;
/**
* @author wangshaoyu
*/
public class POJ3320JessicasReadingProblem {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StreamTokenizer st = new StreamTokenizer(br);
static int nextInt() throws IOException {
st.nextToken();
return (int) st.nval;
}
public static void main(String[] args) throws IOException {
int p = nextInt(); // 这本书有 p 页
int[] nums = new int[p];
// 计算全部知识点的总数
HashSet<Integer> hs = new HashSet<>();
for (int i = 0; i < p; i++) {
nums[i] = nextInt(); // 第 i 页 的知识点
hs.add(nums[i]);
}
int n = hs.size(); // 一共有 n 个知识点
HashMap<Integer, Integer> hm = new HashMap<>(); // 知识点 -> 出现次数
int start = 0; // 区间左端点
int end = 0; // 区间右端点
int ans = n + 1;
while (true) {
while (end < p && hm.size() < n) {
// 如果 hm 里面没有,就添加进去
if (! hm.containsKey(nums[end])) {
hm.put(nums[end], 1);
}
// 有就加 1
else {
int oldValue = hm.get(nums[end]);
hm.replace(nums[end], oldValue + 1);
}
end++;
}
if (hm.size() < n) {
break;
}
ans = Math.min(ans, end - start);
int old = hm.get(nums[start]);
// 这里要删掉,不要减 1,减 1 为 0 但是这个 key 还是存在
if (old == 1) {
hm.remove(nums[start]);
}
else {
hm.replace(nums[start], old - 1);
}
start++;
}
System.out.println(ans);
}
}