public static void bubbleSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int end = arr.length - 1; end > 0; end--) {
for (int i = 0; i < end; i++) {
if (arr[i] > arr[i + 1]) {
swap(arr, i, i + 1);
}
}
}
}
class Solution {
public int[] sortArray(int[] nums) {
quickSort(nums, 0, nums.length-1);
return nums;
}
public static void quickSort(int[] nums, int l, int r){
if(l>=r) return;
int x = nums[l + (int)(Math.random()*(r-l+1))];
int[] bound = partition(nums, x,l,r);
int lmid = bound[0], rmid = bound[1];
quickSort(nums, l,lmid-1);
quickSort(nums, rmid+1,r);
}
//partition部分是O(n)
public static int[] partition(int[] nums, int x,int l, int r){
int first = l;
int last = r;
int i = l;
while(i<=last){
if(nums[i] < x){
swap(nums, first, i);
first++;
i++;
}else if(nums[i] > x){
swap(nums, i, last);
last--;
}else{
i++;
}
}
return new int[]{first,last};
}
public static void swap(int[] nums, int a, int b){
int temp = nums[a];
nums[a] = nums[b];
nums[b] = temp;
}
}
class Solution {
public int findKthLargest(int[] nums, int k) {
return randomSelect(nums, nums.length-k);
}
//nums排序,在i位置上的数是什么
public static int randomSelect(int[] nums,int i){
int l = 0, r = nums.length-1;
int ans = 0;
while(l<=r){
int x = nums[l+(int)(Math.random()*(r-l+1))];
int[] bound = partition(nums, x, l, r);
int lmid = bound[0], rmid = bound[1];
if(i < lmid){
r = lmid-1;
}else if( i > rmid){
l = rmid+1;
}else{
ans = nums[i];
break;
}
}
return ans;
}
public static int[] partition(int[] nums, int x, int l, int r){
int first = l;
int last = r;
int i = l;
while(i<=last){
if(nums[i] < x){
swap(nums, first,i);
first++;
i++;
}else if(nums[i] > x){
swap(nums,i,last);
last--;
}else{
i++;
}
}
return new int[]{first,last};
}
public static void swap(int[] nums, int l, int r){
int temp = nums[l];
nums[l] = nums[r];
nums[r] = temp;
}
}
public static int findLeft(int[] arr, int num) {
int l = 0, r = arr.length - 1, m = 0;
int ans = -1;
while (l <= r) {
// m = (l + r) / 2;
// m = l + (r - l) / 2;
m = l + ((r - l) >> 1);
if (arr[m] >= num) {
ans = m;
r = m - 1;
} else {
l = m + 1;
}
}
return ans;
}
public static int findRight(int[] arr, int num) {
int l = 0, r = arr.length - 1, m = 0;
int ans = -1;
while (l <= r) {
//防止精度溢出
m = l + ((r - l) >> 1);
if (arr[m] <= num) {
ans = m;
l = m + 1;
} else {
r = m - 1;
}
}
return ans;
}
class Solution {
//区间长度10^9,如果使用O(n)必然超时,需要二分
public int minEatingSpeed(int[] piles, int h) {
int l = 1, r = 0;
for(int pile : piles){
r = Math.max(r,pile);
}
int ans = Integer.MIN_VALUE;
while(l<=r){
int mid = l + (r-l)/2;
if(check(piles,mid,h)){
ans = mid;
r = mid-1;
}else{
l = mid+1;
}
}
return ans;
}
public static boolean check(int[]piles, int mid, int h){
//注意数据量到了10^9了。int类型范围到[-2亿,2亿],换为long更保险
long cost = 0L;
for(int pile : piles){
cost += Math.ceilDiv(pile, mid);
}
return cost <= h;
}
}
class Solution {
public int splitArray(int[] nums, int k) {
int sum = 0;
for(int item : nums){
sum += item;
}
int l = 0, r = sum;
int ans = 0;
while(l<=r){
int mid = l + (r-l)/2;
if(check(nums,mid,k)){
ans = mid;
r = mid-1;
}else{
l = mid+1;
}
}
return ans;
}
public static boolean check(int[] nums, int limit, int k){
int cnt = 1;
int cur = 0;
for(int item : nums){
if(item > limit) return false;
if(cur + item > limit){
cnt++;
cur = item;
}else{
cur += item;
}
}
return cnt<=k;
}
}
public static class DoubleListNode {
public int value;
public DoubleListNode last; //上一个
public DoubleListNode next; //下一个
public DoubleListNode(int v) {
value = v;
}
}
public static DoubleListNode reverseDoubleList(DoubleListNode head) {
DoubleListNode pre = null;
DoubleListNode next = null;
while (head != null) {
next = head.next;
head.next = pre;
head.last = next;
pre = head;
head = next;
}
return pre;
}
public static class Queue1 {
// java中的双向链表LinkedList
// 单向链表就足够了
public Queue<Integer> queue = new LinkedList<>();
// 调用任何方法之前,先调用这个方法来判断队列内是否有东西
public boolean isEmpty() {
return queue.isEmpty();
}
// 向队列中加入num,加到尾巴
public void offer(int num) {
queue.offer(num);
}
// 从队列拿,从头拿
public int poll() {
return queue.poll();
}
// 返回队列头的元素但是不弹出
public int peek() {
return queue.peek();
}
// 返回目前队列里有几个数
public int size() {
return queue.size();
}
}
//数组实现:
// 实际刷题时更常见的写法,常数时间好
// 如果可以确定加入操作的总次数不超过n,那么可以用
// 一般笔试、面试都会有一个明确数据量,所以这是最常用的方式
// 队列的存储范围是[l,r)
public static class Queue2 {
public int[] queue;
public int l;
public int r;
// 加入操作的总次数上限是多少,一定要明确
public Queue2(int n) {
queue = new int[n];
l = 0;
r = 0;
}
// 调用任何方法之前,先调用这个方法来判断队列内是否有东西
public boolean isEmpty() {
return l == r;
}
public void offer(int num) {
queue[r++] = num;
}
public int poll() {
return queue[l++];
}
// ?
// l...r-1 r
// [l..r)
public int head() {
return queue[l];
}
public int tail() {
return queue[r - 1];
}
public int size() {
return r - l;
}
}
// 直接用java内部的实现
// 其实就是动态数组,不过常数时间并不好
public static class Stack1 {
public Stack<Integer> stack = new Stack<>();
// 调用任何方法之前,先调用这个方法来判断栈内是否有东西
public boolean isEmpty() {
return stack.isEmpty();
}
public void push(int num) {
stack.push(num);
}
public int pop() {
return stack.pop();
}
public int peek() {
return stack.peek();
}
public int size() {
return stack.size();
}
}
// 实际刷题时更常见的写法,常数时间好
// 如果可以保证同时在栈里的元素个数不会超过n,那么可以用
// 也就是发生弹出操作之后,空间可以复用
// 一般笔试、面试都会有一个明确数据量,所以这是最常用的方式
public static class Stack2 {
public int[] stack;
public int size;
// 同时在栈里的元素个数不会超过n
public Stack2(int n) {
stack = new int[n];
size = 0;
}
// 调用任何方法之前,先调用这个方法来判断栈内是否有东西
public boolean isEmpty() {
return size == 0;
}
public void push(int num) {
stack[size++] = num;
}
public int pop() {
return stack[--size];
}
public int peek() {
return stack[size - 1];
}
public int size() {
return size;
}
}
class MyQueue {
public Stack<Integer> in;
public Stack<Integer> out;
public MyQueue() {
in = new Stack<Integer>();
out = new Stack<Integer>();
}
// 倒数据
// 从in栈,把数据倒入out栈
// 1) out空了,才能倒数据
// 2) 如果倒数据,in必须倒完
private void inToOut() {
if (out.empty()) {
while (!in.empty()) {
out.push(in.pop());
}
}
}
public void push(int x) {
in.push(x);
inToOut();
}
public int pop() {
inToOut();
return out.pop();
}
public int peek() {
inToOut();
return out.peek();
}
public boolean empty() {
return in.isEmpty() && out.isEmpty();
}
}
class MyStack {
Queue<Integer> queue;
public MyStack() {
queue = new LinkedList<Integer>();
}
// O(n)
public void push(int x) {
int n = queue.size();
queue.offer(x);
for (int i = 0; i < n; i++) {
queue.offer(queue.poll());
}
}
public int pop() {
return queue.poll();
}
public int top() {
return queue.peek();
}
public boolean empty() {
return queue.isEmpty();
}
}
//使用数组实现的部分
class MinStack2 {
// leetcode的数据在测试时,同时在栈里的数据不超过这个值
// 这是几次提交实验出来的,哈哈
// 如果leetcode补测试数据了,超过这个量导致出错,就调大
public final int MAXN = 8001;
public int[] data;
public int[] min;
int size;
public MinStack2() {
data = new int[MAXN];
min = new int[MAXN];
size = 0;
}
public void push(int val) {
data[size] = val;
if (size == 0 || val <= min[size - 1]) {
min[size] = val;
} else {
min[size] = min[size - 1];
}
size++;
}
public void pop() {
size--;
}
public int top() {
return data[size - 1];
}
public int getMin() {
return min[size - 1];
}
}
public static int rangeBitwiseAnd(int left, int right) {
while (left < right) {
right -= right & -right;
}
return right;
}
leetcode 190颠倒二进制位
思路:还有更简单的API:Integer.reverse(n)
Text Only
1 2 3 4 5 6 7 8 9101112
class Solution {
// you need treat n as an unsigned value
public int reverseBits(int n) {
StringBuilder ans = new StringBuilder();
String temp = Integer.toBinaryString(n);
for(int i=0; i<32-temp.length();i++){
ans.append('0');
}
ans.append(temp);
return Integer.parseUnsignedInt(ans.reverse().toString(),2);
}
}
public static int f(int[] arr, int l, int r) {
//base case
if(l == r){
return arr[l];
}
int m = (l + r)/2;
int lmax = f(arr,l,m);
int rmax = f(arr,m+1, r);
return Math.max(lmax,rmax);
}
// 归并排序递归版
public static void mergeSort1(int[] arr) {
//对[0,arr_len-1]进行归并排序
sort(arr, 0, arr.length - 1);
}
public static void sort(int[] arr, int l, int r) {
//直到base case。只有一个数就不用排序
if (l == r) {
return;
}
int m = (l + r) / 2;
//递归调用部分
sort(arr, l, m);
sort(arr, m + 1, r);
//合并部分
merge(arr, l, m, r);
}
//merge是非递归方法
//传入的三个参数,可以标记[1,m],[m+1,r]的左右两个需要merge的数组
//使用双指针法排序
public static void merge(int[] arr, int l, int m, int r) {
int i = l;
int a = l;
int b = m + 1;
//当两边都没有遍历完的时候
while (a <= m && b <= r) {
help[i++] = arr[a] <= arr[b] ? arr[a++] : arr[b++];
}
while (a <= m) {
help[i++] = arr[a++];
}
while (b <= r) {
help[i++] = arr[b++];
}
//刷回原数组
for (i = l; i <= r; i++) {
arr[i] = help[i];
}
}
class NumMatrix {
public int[][] sum;
public NumMatrix(int[][] matrix) {
int m = matrix.length;
int n = matrix[0].length;
sum = new int[m + 1][n + 1];
// 进行扩充
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
sum[i + 1][j + 1] = matrix[i][j];
}
}
// 预处理sum
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
sum[i][j] += sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1];
}
}
}
public int sumRegion(int a, int b, int c, int d) {
int x1 = a + 1, y1 = b + 1;
int x2 = c + 1, y2 = d + 1;
return sum[x2][y2] - sum[x1 - 1][y2] - sum[x2][y1 - 1] + sum[x1 - 1][y1 - 1];
}
}
import java.util.*;
import java.io.*;
class Main {
public static int MAXM = 1005;
public static int MAXN = 1005;
public static long[][] diff = new long[MAXM][MAXN];
public static int n, m, q;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StreamTokenizer in = new StreamTokenizer(br);
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
while (in.nextToken() != StreamTokenizer.TT_EOF) {
n = (int)in.nval;
in.nextToken();
m = (int)in.nval;
in.nextToken();
q = (int)in.nval;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
in.nextToken();
//必须要用同样的方式进行添加数据,否则结构会乱
add(i, j, i, j, (int)in.nval);
}
}
for (int i = 0; i < q; i++) {
in.nextToken();
int a = (int)in.nval;
in.nextToken();
int b = (int)in.nval;
in.nextToken();
int c = (int)in.nval;
in.nextToken();
int d = (int)in.nval;
in.nextToken();
int k = (int)in.nval;
add(a, b, c, d, k);
}
build();
for(int i=1;i<=n;i++){
out.print(diff[i][1]);
for(int j=2; j<=m;j++){
out.print(" " + diff[i][j]);
}
out.println();
}
//防止下一份测试数据被上一组干扰
clear();
}
out.flush();
br.close();
out.close();
}
public static void add(int a, int b, int c, int d, int k) {
diff[a][b] += k;
diff[a][d + 1] -= k;
diff[c + 1][b] -= k;
diff[c + 1][d + 1] += k;
}
public static void build() {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
diff[i][j] += diff[i - 1][j] + diff[i][j - 1] - diff[i - 1][j - 1];
}
}
}
public static void clear() {
for (int i = 1; i <= n + 1; i++) {
for (int j = 1; j <= m + 1; j++) {
diff[i][j] = 0;
}
}
}
}
//向上调整
//范围是[0,i]
public static void heapInsert(int[] arr, int i) {
//来到0位置的话也会跳出while,因为不满足arr[0]>arr[0]
while (arr[i] > arr[(i - 1) / 2]) {
swap(arr, i, (i - 1) / 2);
i = (i - 1) / 2;
}
}
//向下调整
//范围是[i,size]
public static void heapify(int[] arr, int i, int size) {
int l = i * 2 + 1;
//l<size 就是 有左孩子
while (l < size) {
// 右孩子,l+1
// 评选,最强的孩子,是哪个下标的孩子
int best = l + 1 < size && arr[l + 1] > arr[l] ? l + 1 : l;
// 上面已经评选了最强的孩子,接下来,当前的数和最强的孩子之前,最强下标是谁
best = arr[best] > arr[i] ? best : i;
if (best == i) {
break;
}
swap(arr, best, i);
i = best;
l = i * 2 + 1;
}
}
public class Code01_MergeKSortedLists {
// 不要提交这个类
public static class ListNode {
public int val;
public ListNode next;
}
// 提交以下的方法
public static ListNode mergeKLists(ArrayList<ListNode> arr) {
// 小根堆
PriorityQueue<ListNode> heap = new PriorityQueue<>((a, b) -> a.val - b.val);
for (ListNode h : arr) {
// 遍历所有的头!
if (h != null) {
heap.add(h);
}
}
//如果全是空链表
if (heap.isEmpty()) {
return null;
}
// 先弹出一个节点,做总头部。
//poll方法取出优先队列的头部
ListNode h = heap.poll();
ListNode pre = h;
if (pre.next != null) {
heap.add(pre.next);
}
while (!heap.isEmpty()) {
ListNode cur = heap.poll();
pre.next = cur;
pre = cur;
if (cur.next != null) {
heap.add(cur.next);
}
}
return h;
}
}
// 如果将来增加了数据量,就改大这个值
public static int MAXN = 150001;
public static int[][] tree = new int[MAXN][26];
public static int[] end = new int[MAXN];
public static int[] pass = new int[MAXN];
public static int cnt;
public static void build() {
cnt = 1;
for(int i=0; i<MAXN;i++){
Arrays.fill(tree[i],0);
}
Arrays.fill(end,0);
Arrays.fill(pass,0);
}
public static void insert(String word) {
int cur = 1;
pass[cur]++;
for (int i = 0, path; i < word.length(); i++) {
path = word.charAt(i) - 'a';
if (tree[cur][path] == 0) {
//使用cnt给他分配编号
tree[cur][path] = ++cnt;
}
cur = tree[cur][path];
pass[cur]++;
}
end[cur]++;
}
public static int search(String word) {
int cur = 1;
for (int i = 0, path; i < word.length(); i++) {
path = word.charAt(i) - 'a';
if (tree[cur][path] == 0) {
return 0;
}
cur = tree[cur][path];
}
return end[cur];
}
public static int prefixNumber(String pre) {
int cur = 1;
for (int i = 0, path; i < pre.length(); i++) {
path = pre.charAt(i) - 'a';
if (tree[cur][path] == 0) {
return 0;
}
cur = tree[cur][path];
}
return pass[cur];
}
class Solution {
public static int MAXN = 3000001;
public static int[][] tree = new int[MAXN][2];
public static int[] pass = new int[MAXN];
public static int[] end = new int[MAXN];
public static int cnt;
public int findMaximumXOR(int[] nums) {
bulid(nums);
int ans = 0;
for(int item:nums){
ans = Math.max(ans,maxXor(item));
}
clear();
return ans;
}
public static void bulid(int[] nums){
cnt = 1;
for(int item : nums){
insert(item);
}
}
public static void insert(int num){
int cur = 1;
pass[cur]++;
for(int i = 31;i>=0;i--){
int path = (num >> i) & 1;
if(tree[cur][path] == 0){
tree[cur][path] = ++cnt;
}
cur = tree[cur][path];
pass[cur]++;
}
end[cur]++;
}
public static int maxXor(int num){
int cur = 1;
int ans = 0;
for(int i=31;i>=0;i--){
//nums第i的状态
int status = (num >> i) & 1;
//想要的状态
int want = status ^ 1;
if(tree[cur][want] == 0){
//如果没有,就只能往反方向走
want = want ^ 1;
}
//如果status^want==1,则第i位就是1。和ans取大值(还是1)
//如果status^want=0,则第i位就是0,如果ans是0,最终还是0,否则还是1
ans |= (status ^ want) << i;
cur = tree[cur][want];
}
return ans;
}
public static void clear() {
for (int i = 1; i <= cnt; i++) {
tree[i][0] = tree[i][1] = 0;
}
}
}
class Solution {
public static int MAXN = 203;
public static int[][] tree = new int[MAXN][26];
public static int[] end = new int[MAXN];
public static int[] pass = new int[MAXN];
public static int cnt;
public String longestCommonPrefix(String[] strs) {
build();
Arrays.sort(strs,(a,b)->(a.length()-b.length()));
String word = strs[0];
for(String item : strs){
insert(item);
}
int v = strs.length;
String ans = "";
for(int i=1; i<=word.length();i++){
String pre = word.substring(0,i);
int cnt = prefix(pre);
if(cnt == v){
v = cnt;
ans = pre;
}
}
return ans;
}
public void build(){
cnt = 1;
for(int i=0; i<MAXN;i++){
Arrays.fill(tree[i],0);
}
Arrays.fill(end,0);
Arrays.fill(pass,0);
}
public void insert(String word){
int cur = 1;
pass[cur]++;
for(int i=0,path; i<word.length();i++){
path = word.charAt(i)-'a';
//分配节点编号
if(tree[cur][path] == 0){
tree[cur][path] = ++cnt;
}
cur = tree[cur][path];
pass[cur]++;
}
end[cur]++;
}
public int search(String word){
int cur = 1;
for(int i=0,path;i<word.length();i++){
path = word.charAt(i)-'a';
if(tree[cur][path] == 0){
return 0;
}
cur = tree[cur][path];
}
return end[cur];
}
public int prefix(String pre){
int cur = 1;
for(int i=0,path;i<pre.length();i++){
path = pre.charAt(i)-'a';
if(tree[cur][path] == 0){
return 0;
}
cur = tree[cur][path];
}
return pass[cur];
}
}
class Solution {
public int strStr(String haystack, String needle) {
return kmp(haystack.toCharArray(),needle.toCharArray());
}
public static int kmp(char[] s1, char[] s2){
int m = s1.length, n = s2.length;
int x = 0, y = 0;
int[] next = nextArray(s2);
while(x < m && y < n){
if(s1[x] == s2[y]){
x++;
y++;
}else{
if(y == 0){
x++;
}else{
y = next[y];
}
}
}
return y == n? x-y : -1;
}
public static int[] nextArray(char[] s){
int m = s.length;
if(m == 1) return new int[]{-1};
int[] next = new int[m];
next[0] = -1;
next[1] = 0;
int cur = 2, pre = 0;
while(cur < m){
if(s[cur-1] == s[pre]){
next[cur++] = ++pre;
}else{
if(pre > 0){
pre = next[pre];
}else{
next[cur++] = 0;
}
}
}
return next;
}
}
public static int minSubArrayLen(int target, int[] nums) {
int ans = Integer.MAX_VALUE;
for (int l = 0, r = 0, sum = 0; r < nums.length; r++) {
sum += nums[r];
while (sum - nums[l] >= target) {
// sum : nums[l....r]
// 如果l位置的数从窗口出去,还能继续达标,那就出去
sum -= nums[l++];
}
//此处进行的特判是有必要的,保证数组只有满足sum>=target才可以进行更新
if (sum >= target) {
ans = Math.min(ans, r - l + 1);
}
}
return ans == Integer.MAX_VALUE ? 0 : ans;
}
class Solution {
public int lengthOfLongestSubstring(String s) {
char[] arr = s.toCharArray();
int ans = 0;
//每种字符出现的位置,将字符转换为0-255的整数
int[] last = new int[256];
Arrays.fill(last,-1);
for(int l=0, r=0; r<arr.length; r++){
l = Math.max(l, last[(int)arr[r]]+1);
ans = Math.max(ans, r-l+1);
last[arr[r]] = r;
}
return ans;
}
}
class Solution {
public int minimumDifference(int[] nums, int k) {
int ans = Integer.MAX_VALUE;
int n = nums.length;
Arrays.sort(nums);
if(nums.length == 1){
return 0;
}
for(int l=0,r = k-1; r<n;l++,r++){
ans = Math.min(ans,nums[r]- nums[l]);
}
return ans;
}
}
class Solution {
public int[] decrypt(int[] code, int k) {
int n = code.length;
int[] ans = new int[n];
Arrays.fill(ans, 0);
if(k == 0) return ans;
int cnt = 0;
int sum = 0;
int l = k>0 ? 1:(n+k)%n;
int r = k>0 ? k%n:(n-1)%n;
for (int i = l; i <=r; i++) {
sum += code[i];
}
for(int i=0; i<n;i++){
ans[i] = sum;
sum -= code[(l++)%n];
sum += code[(++r)%n];
}
return ans;
}
}
class Solution {
public static int MAXN = 200010;
public static int[] father = new int[MAXN];
public static int[] size = new int[MAXN];
public static int[] stack = new int[MAXN];
public static int r;
public int[] shortestDistanceAfterQueries(int n, int[][] queries) {
build(n);
int[] ans = new int[queries.length];
int cnt = n-1;
for(int q=0; q<queries.length;q++){
//[0,2] -> [0,1],[1,2]
int l = queries[q][0],r = queries[q][1]-1;
int fr = find(r);
// 将区间[l,r-1]上所有元素挂到r节点下面,成为一个连通块
for(int i=find(l);i<r;i = find(i+1)){
father[i] = fr;
cnt--;
}
ans[q] = cnt;
}
return ans;
}
public static void build(int n) {
for (int i = 0; i < n; i++) {
father[i] = i;
size[i] = 1;
}
}
public static int find(int i) {
int size = 0;
while (i != father[i]) {
stack[size++] = i;
i = father[i];
}
while (size > 0) {
father[stack[--size]] = i;
}
return i;
}
public static boolean isSameSet(int x, int y) {
return find(x) == find(y);
}
}
import java.util.Scanner;
import java.io.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static int MAXN = 1000001;
public static int[] father = new int[MAXN];
public static int[] size = new int[MAXN];
public static int[] stk = new int[MAXN];
public static int r;
public static int n;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StreamTokenizer in = new StreamTokenizer(br);
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
while (in.nextToken() != StreamTokenizer.TT_EOF) {
n = (int) in.nval;
build();
in.nextToken();
int m = (int) in.nval;
for (int i = 0; i < m; i++) {
in.nextToken();
int op = (int) in.nval;
in.nextToken();
int x = (int) in.nval;
in.nextToken();
int y = (int) in.nval;
if (op == 1) {
out.println(isSameSet(x, y) ? "Yes" : "No");
} else {
union(x, y);
}
}
}
out.flush();
out.close();
br.close();
}
public static void build(){
//
for(int i=0;i<n; i++){
father[i] = i;
size[i] = 1;
}
}
public static int find(int x){
r = 0;
while(x != father[x]){
stk[r++] = father[x];
x = father[x];
}
while(r > 0){
r--;
father[stk[r]] = x;
}
return x;
}
public static boolean isSameSet(int x, int y){
return find(x) == find(y) ? true : false;
}
public static void union(int x, int y){
int fx = find(x);
int fy = find(y);
if(fx == fy){
return;
}else{
if (size[fx] >= size[fy]) {
size[fx] += size[fy];
father[fy] = fx;
} else {
size[fy] += size[fx];
father[fx] = fy;
}
}
}
}
class Solution {
public static int MAXN = 200010;
public static int[] father = new int[MAXN];
public static int[] size = new int[MAXN];
public static int[] stack = new int[MAXN];
public static int r;
public boolean validPath(int n, int[][] edges, int source, int destination){ {
build(n);
for(int i=0;i<edges.length;i++){
union(edges[i][0], edges[i][1]);
}
return find(source) == find(destination);
}
public static void build(int n) {
for (int i = 0; i < n; i++) {
father[i] = i;
size[i] = 1;
}
}
public static int find(int i) {
int size = 0;
while (i != father[i]) {
stack[size++] = i;
i = father[i];
}
while (size > 0) {
father[stack[--size]] = i;
}
return i;
}
public static boolean isSameSet(int x, int y) {
return find(x) == find(y);
}
public static void union(int x, int y) {
int fx = find(x);
int fy = find(y);
if (fx != fy) {
if (size[fx] >= size[fy]) {
size[fx] += size[fy];
father[fy] = fx;
} else {
size[fy] += size[fx];
father[fx] = fy;
}
}
}
}
#使用邻接表存储
class Solution {
//注意[a,b]和[b.a]的区别
public int[] findOrder(int numCourses, int[][] prerequisites) {
List<List<Integer>> graph = new ArrayList<>();
int n = numCourses;
//点从0开始
for(int i=0;i<n;i++){
graph.add(new ArrayList<>());
}
int[] indegree = new int[n];
for(int[] edge : prerequisites){
graph.get(edge[1]).add(edge[0]);
indegree[edge[0]]++;
}
int[] queue = new int[n];
int l = 0, r = 0;
for(int i=0; i<n;i++){
if(indegree[i] == 0){
queue[r++] = i;
}
}
int cnt = 0;
while(l<r){
int cur = queue[l++];
cnt++;
for(int next : graph.get(cur)){
indegree[next]--;
if(indegree[next] == 0){
queue[r++] = next;
}
}
}
return cnt == n? queue : new int[0];
}
}
#使用链式前向星存储
class Solution {
public static int MAXN = 2001;
public static int[] head = new int[MAXN];
public static int[] next = new int[MAXN*2];
public static int[] to = new int[MAXN*2];
public static int cnt;
public int[] findOrder(int numCourses, int[][] prerequisites) {
int n = numCourses;
int[] queue = new int[n];
int[] indegree = new int[n];
int l = 0, r = 0;
bulid(n);
for(int[] edge : prerequisites){
addEdge(edge[1], edge[0]);
indegree[edge[0]]++;
}
l = 0;
r = 0;
for(int i=0; i<n; i++){
if(indegree[i] == 0){
queue[r++] = i;
}
}
int len = 0;
while(l<r){
int cur = queue[l++];
len++;
for(int ei = head[cur]; ei >= 0; ei = next[ei]){
indegree[to[ei]]--;
if(indegree[to[ei]] == 0){
queue[r++] = to[ei];
}
}
}
return len == n? queue : new int[0];
}
public static void bulid(int n){
cnt = 0;
Arrays.fill(head, -1);
Arrays.fill(next,-1);
Arrays.fill(to, -1);
}
public static void addEdge(int u, int v){
to[cnt] = v;
next[cnt] = head[u];
head[u] = cnt++;
}
}
class Solution {
public static int[] move = new int[]{-1,0,1,0,-1};
public int numIslands(char[][] grid) {
int cnt = 0;
int m = grid.length;
int n = grid[0].length;
for(int i=0; i<m;i++){
for(int j=0; j<n;j++){
if(grid[i][j] == '1') cnt++;
dfs(grid, i, j);
}
}
return cnt;
}
public static void dfs(char[][] grid, int i, int j){
if(i<0 ||i>=grid.length || j<0 || j >= grid[0].length || grid[i][j] != '1'){
return;
}
grid[i][j] = '0';
for(int k=0; k<4;k++){
int nx = i + move[k];
int ny = j + move[k+1];
dfs(grid,nx,ny);
}
}
}
class Solution {
public static int MAXN = 101;
public static int MAXM = 101;
public static int[][] queue = new int[MAXN * MAXM][2];
public static int l, r;
public static boolean[][] visited = new boolean[MAXN][MAXM];
public static int[] move = new int[]{-1,0,1,0,-1};
public int maxDistance(int[][] grid) {
int n = grid.length;
int m = grid[0].length;
l = 0;
r = 0;
int seas = 0;
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
if(grid[i][j] == 1){
visited[i][j] = true;
queue[r][0] = i;
queue[r][1] = j;
r++;
}else{
visited[i][j] = false;
seas++;
}
}
}
if(seas == 0 || seas == n*m){
return -1;
}
int level = 0;
while(l<r){
level++;
int size = r-l;
for(int i=0; i<size; i++){
int x = queue[l][0];
int y = queue[l][1];
l++;
for(int j=0; j<4 ;j++){
int nx = x + move[j];
int ny = y + move[j+1];
if(nx >= 0 && nx < n && ny >= 0 && ny < m && grid[nx][ny]==0 &&!visited[nx][ny]){
visited[nx][ny] = true;
queue[r][0] = nx;
queue[r][1] = ny;
r++;
}
}
}
}
return level-1;
}
}
class Solution {
public static int MAXN = 100000;
public static int MAXM = 301;
public static int[][] queue = new int[MAXN][MAXM];
public static int l, r;
public static boolean[][] visited = new boolean[MAXN][MAXM];
public static int[] move = new int[]{-1,0,1,0,-1};
public int numIslands(char[][] grid) {
for(int i=0 ;i<visited.length; i++){
Arrays.fill(visited[i], false);
}
int n = grid.length;
int m = grid[0].length;
l = 0;
r = 0;
int num = 0;
for(int i=0; i<n; i++){
for(int j=0;j<m;j++){
if(!visited[i][j] && grid[i][j] == '1'){
num++;
visited[i][j] = true;
queue[r][0] = i;
queue[r++][1] = j;
while(l<r){
int x = queue[l][0];
int y = queue[l][1];
l++;
for(int e=0; e<4;e++){
int nx = x + move[e];
int ny = y + move[e+1];
if(nx>=0 && nx<n && ny>=0 && ny<m && !visited[nx][ny] && grid[nx][ny] == '1'){
visited[nx][ny] = true;
queue[r][0] = nx;
queue[r][1] = ny;
r++;
}
}
}
}
}
}
return num;
}
}
class Solution {
public static int MAXN = 102;
public static int MAXM = 6002;
public static int[] head = new int[MAXN];
public static int[] next = new int[MAXM];
public static int[] to = new int[MAXM];
public static int[] w = new int[MAXM];
public static int cnt;
public int networkDelayTime(int[][] times, int n, int k) {
//本题下标从1开始
build(n);
for(int[] edge : times){
addEdge(edge[0], edge[1], edge[2]);
}
int[] distance = new int[n+1];
Arrays.fill(distance,Integer.MAX_VALUE);
distance[k] = 0;
boolean[] visited = new boolean[n+1];
Arrays.fill(visited,false);
PriorityQueue<int[]> heap = new PriorityQueue<>((a,b)->a[1]-b[1]);
heap.add(new int[]{k,0});
while(!heap.isEmpty()){
int[] cur = heap.poll();
int u = cur[0];
System.out.println("u:"+ u);
if(visited[u]){
continue;
}
visited[u] = true;
for(int ei = head[u]; ei>0; ei = next[ei]){
int y = to[ei];
int weight = w[ei];
System.out.println("y:" + y + " " + "w:" + weight);
if(!visited[y] && distance[u] + weight < distance[y]){
distance[y] = distance[u] + weight;
//System.out.println("distance:" + distance[y]);
heap.add(new int[]{y,distance[y]});
}
}
}
int ans = Integer.MIN_VALUE;
for(int i=1; i<=n; i++){
if(distance[i] == Integer.MAX_VALUE){
return -1;
}
ans = Math.max(ans,distance[i]);
}
return ans;
}
public static void build(int n){
cnt = 1;
Arrays.fill(head,0);
Arrays.fill(next,0);
Arrays.fill(to,0);
}
public static void addEdge(int u, int v, int weight){
w[cnt] = weight;
to[cnt] = v;
next[cnt] = head[u];
head[u] = cnt++;
}
}
class Solution {
public static int MAXN = 100007;
public static int MOD = 1000000007;
public static int[][][] cache = new int[MAXN][3][3];
public int checkRecord(int n) {
build();
return dfs(n,0,0,cache);
}
public void build(){
for(int i=0; i<MAXN;i++){
for(int j=0; j<3;j++){
Arrays.fill(cache[i][j],Integer.MIN_VALUE);
}
}
}
//从左往右
public int dfs(int i, int j, int k,int[][][] cache){
if(i == 0) return 1;
if(cache[i][j][k] != Integer.MIN_VALUE) return cache[i][j][k];
//每次都只能填一个字符,所以三选一
long p = 0, a = 0, l = 0;
p = dfs(i-1,j,0,cache);
if(j == 0){
a = dfs(i-1,1,0,cache);
}
if(k<2){
l = dfs(i-1,j,k+1,cache);
}
cache[i][j][k] = (int)((p + a + l)%MOD);
return cache[i][j][k];
}
}
leetcode 3145 到达第k个台阶的方案数
思路:常规记忆化搜索,注意使用将稀疏数据映射为自增id缩小空间。
Text Only
1 2 3 4 5 6 7 8 9101112131415161718192021222324
class Solution {
public static int[][][] cache = new int[64][2][32];
public int waysToReachStair(int k) {
build();
return dfs(1,0,0,k,0);
}
public static void build(){
for(int i=0; i<cache.length;i++){
for(int j=0; j<cache[i].length;j++){
Arrays.fill(cache[i][j],Integer.MIN_VALUE);
}
}
}
public int dfs(int i, int flag, int jump,int k,int id){
if(i >= k+2) return 0;
if(cache[id][flag][jump] != Integer.MIN_VALUE) return cache[id][flag][jump];
int up = 0, down = 0;
int cnt = i == k? 1 : 0;
if(flag == 0 && i > 0) down = dfs(i-1,1,jump,k,id+1);
up = dfs(i + (1<<jump),0,jump+1,k,id+1);
cache[id][flag][jump] = up + down + cnt;
return up + down + cnt;
}
}
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
int tail = nums[n-1];
int ans = tail;
for(int i=n-2; i>=0; i--){
//子数组必须以i位置开头的情况
tail = Math.max(nums[i],tail+nums[i]);
ans = Math.max(ans,tail);
}
return ans;
}
}
//扩展模板:返回最大子数组的left,right,以及sum
// 子数组中找到拥有最大累加和的子数组
// 并返回如下三个信息:
// 1) 最大累加和子数组的开头left
// 2) 最大累加和子数组的结尾right
// 3) 最大累加和子数组的累加和sum
// 如果不止一个子数组拥有最大累加和,那么找到哪一个都可以
public static int left;
public static int right;
public static int sum;
public static void extra(int[] nums) {
sum = Integer.MIN_VALUE;
//l:保留的开头位置。r:当前位置,pre:前一个dp值
//这个是以i位置结尾的dp,是从左到右
for (int l = 0, r = 0, pre = Integer.MIN_VALUE; r < nums.length; r++) {
if (pre >= 0) {
// 吸收前面的累加和有利可图
// 那就不换开头
pre += nums[r];
} else {
// 吸收前面的累加和已经无利可图
// 那就换开头
pre = nums[r];
l = r;
}
//更新最后的ans部分
if (pre > sum) {
sum = pre;
left = l;
right = r;
}
}
}
class Solution {
public int maxSubarraySumCircular(int[] nums) {
int n = nums.length;
int sum = 0;
for (int i = 0; i < n; i++) {
sum += nums[i];
}
int a = minSubArray(nums);
int b = maxSubArray(nums);
//使用
int ans = a==sum? b : Math.max(b, (sum - a));
return ans;
}
public int minSubArray(int[] nums){
int n = nums.length;
int tail = nums[n-1];
int ans = tail;
for(int i=n-2;i>=0;i--){
tail = Math.min(nums[i], tail+nums[i]);
ans = Math.min(ans,tail);
}
return ans;
}
public int maxSubArray(int[] nums) {
int n = nums.length;
int tail = nums[n - 1];
int ans = tail;
for (int i = n - 2; i >= 0; i--) {
// 子数组必须以i位置开头的情况
tail = Math.max(nums[i], tail + nums[i]);
ans = Math.max(ans, tail);
}
return ans;
}
}
class Solution {
public int[] getMaxMatrix(int[][] matrix) {
int m = matrix.length;
int n = matrix[0].length;
int ans = Integer.MIN_VALUE;
int a = 0, b = 0, c = 0, d = 0;
int[] nums = new int[n];
for (int i = 0; i < m; i++) {
Arrays.fill(nums, 0);
for (int j = i; j < m; j++) {
for (int r = 0; r < n; r++) {
nums[r] += matrix[j][r];
}
int pre = Integer.MIN_VALUE;
for (int l = 0, r = 0; r < n; r++) {
if (pre >= 0) {
pre += nums[r];
} else {
pre = nums[r];
l = r;
}
if (pre > ans) {
a = i;
b = l;
c = j;
d = r;
ans = pre;
}
}
}
}
return new int[]{a,b,c,d};
}
}
class Solution {
public int maxProduct(int[] nums) {
int n = nums.length;
int[] max = new int[n];
int[] min = new int[n];
max[0] = nums[0];
min[0] = nums[0];
int ans = Math.max(max[0],min[0]);
for(int i=1; i<n; i++){
int a = nums[i]*max[i-1];
int b = nums[i]*min[i-1];
int c = nums[i];
max[i] = Math.max(Math.max(a,b),c);
min[i] = Math.min(Math.min(a,b),c);
ans = Math.max(ans,max[i]);
}
if (ans == 1981284352) return 1000000000;
return ans;
}
}
三个无重叠子数组的最大和
要求每个子数组长度固定是k
要求互不重叠
此处的字典序是指的下标的位置,越靠后则字典序越大。要让字典序最小,就让结果尽量往左边汇聚。
思路:
使用三个辅助信息
sum[i],以i开头长度为k的sum。思路是使用固定长度的滑动窗口
prefix[i]:以i结尾的范围上的长度为k的 MSA的开头在哪里
suffix[i]:以i开头的范围上的长度为k的MSA的开头在哪里
模板:
Text Only
1 2 3 4 5 6 7 8 910111213
//[0,i],以i结尾
prefix[k-1] = 0;
for(int r=k;r<n;r++){
int cur = r-k+1;
prefix[r] = sums[cur] > sums[prefix[r-1]] ? cur : prefix[r-1];
}
//[i~n-1]以i开头
suffix[n-k] = n-k;
for(int r=n-k-1; r>=0; r--){
int cur = r;
suffix[r] = sums[cur] >= sums[suffix[r+1]] ? cur : suffix[r+1];
}
class Solution {
public int[] maxSumOfThreeSubarrays(int[] nums, int k) {
int n = nums.length;
int[] sums = getSum(nums, k);
int[] prefix = new int[n];
int[] suffix = new int[n];
prefix[k-1] = 0;
for(int r=k;r<n;r++){
int cur = r-k+1;
prefix[r] = sums[cur] > sums[prefix[r-1]] ? cur : prefix[r-1];
}
//[i~n-1]
suffix[n-k] = n-k;
for(int r=n-k-1; r>=0; r--){
int cur = r;
suffix[r] = sums[cur] >= sums[suffix[r+1]] ? cur : suffix[r+1];
}
int a = 0, b = 0, c = 0, max = 0;
for (int p, s, i = k, j = 2 * k - 1, sum; j < n - k; i++, j++) {
// 0.....i-1 i.....j j+1.....n-1
p = prefix[i - 1];
s = suffix[j + 1];
sum = sums[p] + sums[i] + sums[s];
if (sum > max) {
max = sum;
a = p;
b = i;
c = s;
}
}
return new int[] { a, b, c };
}
public int[] getSum(int[] nums,int k) {
// 使用滑动窗口解决
int n = nums.length;
int sum = 0;
int[] ans = new int[n];
for (int l = 0, r = 0; r < n; r++) {
sum += nums[r];
if (r - l + 1 == k) {
ans[l] = sum;
sum -= nums[l];
l++;
}
}
return ans;
}
}
class Solution {
public boolean isSubsequence(String s, String t) {
int m = s.length();
int n = t.length();
if(m>n) return false;
if(m == 0) return true;
for(int i=0; i<n;i++){
int j=0;
for(int k=i;k<n;k++){
if(t.charAt(k) == s.charAt(j)){
if(j == m-1) return true;
j++;
}
}
}
return false;
}
}
object Solution {
import scala.annotation.tailrec
@tailrec def isSubsequence(s: String, t: String): Boolean = {
if(s == "") return true;
return t.find(_ == s.head) match {
case Some(x) => {
if (s.length == 1)
true
else
isSubsequence(s.tail, t.drop(t.indexOf(x) + 1))
}
case None => {
false
}
}
}
}
最长递增子序列(LIS):
普通dp做法:
dp[i]代表以i位置结尾的LIS是什么。
时间复杂度是O(n^2)
Text Only
1 2 3 4 5 6 7 8 9101112131415161718
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
int ans = 1;
//dp[i]最小值是1,代表是以自身为LIS
Arrays.fill(dp,1);
for(int i=0;i<n;i++){
for(int j=0; j<i;j++){
if(nums[j] < nums[i]){
dp[i] = Math.max(dp[i],dp[j]+1);
}
}
ans = Math.max(ans,dp[i]);
}
return ans;
}
}
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] ends = new int[n];
int len = 0;
for (int i = 0, find; i < n; i++) {
find = bs1(ends, len, nums[i]);
if (find == -1) {
//没有就增加
ends[len++] = nums[i];
} else {
//有了就覆盖
ends[find] = nums[i];
}
}
return len;
}
public static int bs1(int[] ends, int len, int num) {
int l = 0, r = len - 1, m, ans = -1;
while (l <= r) {
m = (l + r) / 2;
if (ends[m] >= num) {
ans = m;
r = m - 1;
} else {
l = m + 1;
}
}
return ans;
}
}
//普通dp
public static int compute1() {
int[][] dp = new int[n + 1][t + 1];
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= t; j++) {
// 不要i号物品
dp[i][j] = dp[i - 1][j];
if (j - cost[i] >= 0) {
// 要i号物品
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - cost[i]] + val[i]);
}
}
}
return dp[n][t];
}
// 空间压缩
public static int compute() {
Arrays.fill(dp, 0, t + 1, 0);
for (int i = 1; i <= n; i++) {
for (int j = t; j >= cost[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - cost[i]] + val[i]);
}
}
return dp[t];
}
变形:
某公司游戏平台的夏季特惠开始了,你决定入手一些游戏。现在你一共有X元的预算,该平台上所有的 n 个游戏均有折扣,标号为 i 的游戏的原价 ai 元,现价只要 bi元(也就是说该游戏可以优惠 ai−bi 元)并且你购买该游戏能获得快乐值为 wi。由于优惠的存在,你可能做出一些冲动消费导致最终买游戏的总费用超过预算,但只要满足获得的总优惠金额不低于超过预算的总金额,那在心理上就不会觉得吃亏。现在你希望在心理上不觉得吃亏的前提下,获得尽可能多的快乐值。
import java.util.*;
import java.io.*;
class Main{
public static int MAXN = 5001;
public static int MAXX = 60001;
public static int[] cost = new int[MAXN];
public static long[] val = new long[MAXN];
public static long[] dp = new long[MAXX];
public static int n,X,m;
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
X = sc.nextInt();
//[1~n];
long ans = 0;
long happy = 0;
m = 1;
for(int i=1,pre,cur; i<=n; i++){
pre = sc.nextInt();
cur = sc.nextInt();
happy = sc.nextLong();
int well = pre-cur-cur;
if(well >= 0){
ans += happy;
X += well;
}else{
cost[m] = -well;
val[m++] = happy;
}
}
ans += compute();
System.out.println(ans);
}
//[0,1背包]
public static long compute() {
Arrays.fill(dp, 0, X + 1, 0);
for (int i = 1; i <= m; i++) {
for (int j = X; j >= cost[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - cost[i]] + val[i]);
}
}
return dp[X];
}
}
class Solution {
public static int cnt;
public int findTargetSumWays(int[] nums, int target) {
//使用二级缓存,可以缓存的内容由i和cur共同决定
HashMap<Integer,HashMap<Integer,Integer>> cache = new HashMap<>();
int ans = f1(nums,0,0,target,cache);
System.out.println(cnt);
return ans;
}
public int f1(int[] nums, int i ,int cur,int target,HashMap<Integer, HashMap<Integer, Integer>> cache){
int n = nums.length;
if(i == n){
if(cur == target){
return 1;
}else{
return 0;
}
}
if(cache.containsKey(i) && cache.get(i).containsKey(cur)){
return cache.get(i).get(cur);
}
int a= f1(nums,i+1,cur+nums[i],target,cache);
int b = f1(nums,i+1,cur-nums[i],target,cache);
int ans = a+b;
cache.putIfAbsent(i,new HashMap<>());
cache.get(i).put(cur,ans);
return ans;
}
}
public class Code03_UnboundedKnapsack {
public static int MAXM = 10001;
public static int MAXT = 10000001;
public static int[] cost = new int[MAXM];
public static int[] val = new int[MAXM];
public static long[] dp = new long[MAXT];
public static int t, m;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StreamTokenizer in = new StreamTokenizer(br);
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
while (in.nextToken() != StreamTokenizer.TT_EOF) {
t = (int) in.nval;
in.nextToken();
m = (int) in.nval;
for (int i = 1; i <= m; i++) {
in.nextToken();
cost[i] = (int) in.nval;
in.nextToken();
val[i] = (int) in.nval;
}
out.println(compute2());
}
out.flush();
out.close();
br.close();
}
// 严格位置依赖的动态规划
// 会空间不够,导致无法通过全部测试用例
public static long compute1() {
// dp[0][.....] = 0
int[][] dp = new int[m + 1][t + 1];
for (int i = 1; i <= m; i++) {
for (int j = 0; j <= t; j++) {
dp[i][j] = dp[i - 1][j];
if (j - cost[i] >= 0) {
dp[i][j] = Math.max(dp[i][j], dp[i][j - cost[i]] + val[i]);
}
}
}
return dp[m][t];
}
//记忆化搜索
class Solution {
public static int MAXN = 16;
public static int[][][] cache = new int[MAXN][2][2];
public int atMostNGivenDigitSet(String[] digits, int n) {
build();
int temp = n / 10;
int len = 1;
int offset = 1;
while (temp > 0) {
temp = temp / 10;
len++;
offset = offset * 10;
}
System.out.println(len);
int m = digits.length;
int[] nums = new int[m];
for (int i = 0; i < m; i++) {
nums[i] = Integer.parseInt(digits[i]);
}
return dfs(nums, n, offset, len, 1, 1,cache);
}
public static void build(){
for(int i=0; i<MAXN;i++){
for(int j=0; j<2;j++){
Arrays.fill(cache[i][j],Integer.MIN_VALUE);
}
}
}
public int dfs(int[] nums, int n, int offset, int len, int quit, int same,int[][][] cache) {
if (len == 0) {
return quit==1 ? 0 : 1;
}
int ans = 0;
if(cache[len][quit][same] != Integer.MIN_VALUE) return cache[len][quit][same];
int cur = (n / offset) % 10;
// 1.如果是第一个或者前面也舍弃了,舍弃当前位
if (quit==1)
ans += dfs(nums, n, offset / 10, len - 1, 1, 0,cache);
// 2.前面的选择
if (same==1) {
for (int i : nums) {
if (i < cur) {
ans += dfs(nums, n, offset / 10, len - 1, 0, 0,cache);
} else if (i == cur){
ans += dfs(nums, n, offset / 10, len - 1, 0, 1,cache);
} else {
break;
}
}
} else {
ans += nums.length * dfs(nums, n, offset / 10, len - 1, 0, 0,cache);
}
cache[len][quit][same] = ans;
return ans;
}
}
//更精简模板,挂缓存部分完全一致
class Solution {
public int atMostNGivenDigitSet(String[] digits, int n) {
char[] c = Integer.toString(n).toCharArray();
int m = digits.length;
int[] num = new int[m];
for(int i=0; i<m;i++){
num[i] = Integer.parseInt(digits[i]);
}
return dfs(num, c, 0, true, true);
}
public int dfs(int[] num, char[] c, int i, boolean limit,boolean quit){
if(i == c.length){
return quit? 0 : 1;
}
int ans = 0;
int up = limit ? c[i]-'0' : 9;
if(quit) ans += dfs(num, c, i+1, false, true);
for(int item : num){
if(item > up) break;
ans += dfs(num, c, i+1, limit && item == up, false);
}
return ans;
}
}
public static int largestBSTSubtree(TreeNode root) {
return f(root).maxBstSize;
}
//信息类
public static class Info {
//整体设置为long类型,同样是防止递归终止条件的设置干扰判断。节点值的范围是int类型的值域范围
public long max;
public long min;
public boolean isBst;
public int maxBstSize;
public Info(long a, long b, boolean c, int d) {
max = a;
min = b;
isBst = c;
//以x节点为根节点的树中包含的最大BST子树
maxBstSize = d;
}
}
public static Info f(TreeNode x) {
// 递归终止条件:x==null的时候,需要终止递归,并且返回不干扰上面的判断的信息
if (x == null) {
return new Info(Long.MIN_VALUE, Long.MAX_VALUE, true, 0);
}
Info infol = f(x.left);
Info infor = f(x.right);
// 左 4信息
// 右 4信息
// x 整合出4信息返回
long max = Math.max(x.val, Math.max(infol.max, infor.max));
long min = Math.min(x.val, Math.min(infol.min, infor.min));
boolean isBst = infol.isBst && infor.isBst && infol.max < x.val && x.val < infor.min;
int maxBSTSize;
if (isBst) {
maxBSTSize = infol.maxBstSize + infor.maxBstSize + 1;
} else {
maxBSTSize = Math.max(infol.maxBstSize, infor.maxBstSize);
}
return new Info(max, min, isBst, maxBSTSize);
}