Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
kengerlwl committed Mar 19, 2024
1 parent d83825e commit 9598430
Show file tree
Hide file tree
Showing 8 changed files with 357 additions and 43 deletions.
4 changes: 4 additions & 0 deletions DP/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
**注意:有时候边界值不是dp[i][0],dp[0][j] 也可能是dp[i][i]这种中线。**要学会根据状态转移方程,找到dp数组的构建过程。。例如leetcode 5. 最长回文子串


### 非正常顺序转移方程。
牛客:5. 小美的数组操作2.java
比如二维dp[i][j]。计算方式可能并不是j, j+1, j+2.。。。 可能是枚举第i个的可能性,将第i行j个值全部赋予0.然后依次加上一些中间可能性。


# 常见的dp定义

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
long[] nums = new long[n];
long[] preSum = new long[n];
long[] postSum = new long[n];
for (int i = 0; i < n; i++) {
long a = in.nextLong();
nums[i] = a;
}
preSum[0] = nums[0];
for (int i = 1; i < n; i++) {
preSum[i] = preSum[i - 1] + nums[i];
}
postSum[n - 1] = nums[n - 1];
for (int i = n - 2; i >= 0; i--) {
postSum[i] = postSum[i + 1] + nums[i];
}

long ans = 0;
if (n == 2) {
System.out.println(nums[0] * nums[1]);
} else {
ans = nums[0] * nums[1] + postSum[2];
ans = Math.max(ans, nums[n - 1] * nums[n - 2] + preSum[n - 3]);

for (int i = 1; i <= n - 3; i++) {
ans = Math.max(ans, nums[i] * nums[i + 1] + preSum[i - 1] + postSum[i + 2]);

}
System.out.println(ans);
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// 大体上分两种情况
// (1)数组的和(sum),能够整除数组元素的个数(n)。这时,众数就是数组的平均数avg,众数的数量是n。此时计算操作数,那就是每个元素到平均数avg的距离之和除以2,除以二是因为,每一次操作,一个数加一,另一个数减一。因此,计算每个元素到平均数avg的距离之和,相当于把每一次操作算了两遍,后面除以2才是真正的操作数
// (2)数组的和(sum),不能整除数组元素的个数(n)。这时,众数的数量是n-1,把数组中的一个数当做垃圾桶(称之为垃圾数),可以把多余的操作都用在垃圾数上,从而让另外n-1个数相同,达到n-1个众数。运用贪心的思想,这个垃圾数一定是数组的最大值或者最小值。

// 我们以最大值作为垃圾数为例,此时,众数就是剩下n-1个数的平均值(avg),但是有可能不能整除,所以,众数有可能是avg,也有可能是avg+1,(C++默认向下取正)。所以分众数分别是avg和avg+1两种情况讨论,假定众数就是avg,我们现在去计算操作数,定义了两个变量a,b,a用来统计减操作的次数,b用来统计加操作的次数,整体的操作数是max(a,b),a和b的差值就是用在垃圾数上的操作次数。同理,定义c,d去计算众数是avg+1情况下的操作数。最终取min(max(a,b),max(c,d))为最终的操作数。所以,comp函数可以计算数组l到r元素的操作数。

// 同理,最小值作为垃圾数的操作数也通过comp函数计算。最终的结果就是最大值作为垃圾数,和最小值作为垃圾数两种情况下的操作数的最小值
// #include <bits/stdc++.h>
// using namespace std;

// int main() {
// int n;
// cin >> n;
// vector<long long> nums(n);
// for (int i=0; i<n; ++i) {
// cin >> nums[i];
// }
// long long sum = accumulate(nums.begin(), nums.end(), (long long)0);
// if (sum%n==0) {
// long long avg = sum/n;
// long long ans = 0;
// for (auto a:nums) {
// ans += abs(a-avg);
// }
// cout << ans/2 << endl;
// return 0;
// }
// sort(nums.begin(), nums.end());
// function<long long(vector<long long>&, int, int)> comp = [&](vector<long
// long>& nums, int l, int r) {
// long long tot = 0;
// for (int i=l; i<=r; ++i) {
// tot += nums[i];
// }
// long long avg = tot/(r-l+1);
// long long avg2 = avg+1;
// long long a = 0;
// long long b = 0;
// long long c = 0;
// long long d = 0;
// for (int i=l; i<=r; ++i) {
// if (nums[i]>=avg) a+=nums[i]-avg;
// else b+=avg-nums[i];
// if (nums[i]>=avg2) c+=nums[i]-avg2;
// else d+=avg2-nums[i];
// }
// return min(max(a, b), max(c, d));
// };
// long long res1 = comp(nums, 0, n-2);
// long long res2 = comp(nums, 1, n-1);
// cout << min(res1, res2) << endl;
// return 0;
// }
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// 二维动态数组,dp[i][j] 前i个数,和为k且满足要求的组合数量
// dp[i][j] 的转移方程为,求第i行时,
// 第i个数字的所有可能取值(不等于原数组)。然后将其所有可能性,分别计算出来与前面的加上。也就是说,其不是线性的先求j,再求j+1再依次。而是根据第i个数值的选择,依次计算
// #include <bits/stdc++.h>
// using namespace std;
// int main() {
// int n;
// cin >>n;
// vector<int> a(n);
// int sum = 0;

// int mod = 1e9 + 7;
// for(int i = 0; i < n; i++){
// cin >> a[i];
// sum += a[i];
// }
// vector<vector<long>> dp(n+1, vector<long>(sum + 1));
// dp[0][0] = 1;
// for(int i= 1; i <= n; i++) {
// for(int j = 1; j<= sum; j++) {
// for(int k = 1; k <= j-i +1; k++){
// if(a[i - 1] == k) continue;
// dp[i][j] = (dp[i][j] + dp[i -1][j -k]) % mod;
// }
// }
// }

// cout<<dp[n][sum]<<endl;

// 作者:牛客438958669号
// 链接:https://www.nowcoder.com/exam/test/78419136/submission?pid=52007812
// 来源:牛客网
23 changes: 23 additions & 0 deletions README2.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,27 @@ ans = (value -1) / k +1
return b-a;
}
});
```






## 溢出问题
解决java定义long类型却内存溢出的问题
原因是:a和b都是int类型,所以a*b计算的时候会默认将结果转换为int,即使最后赋值给long,此时计算结果已经是错误的了。

解决方案:把a*b计算表达式中任意一个变量转换为long类型。
```
int a = 1000000000;
int b = 20;
long c = a * b;
long d = (long)a * b;
long e = a * (long)b;
System.out.println("a=" + a);
System.out.println("b=" + b);
System.out.println("c=" + c);
System.out.println("d=" + d);
System.out.println("e=" + e);
```
95 changes: 95 additions & 0 deletions 二分/README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,99 @@ private int binarySearch(int[] nums, int target, int left, int right) {
}
}
```





# 二分查找,上下界查找
例如左查找,
如果有目标值,返回目标值最左边的下标(因为可能有多个)。
如果没有目标值,那么返回刚好比目标值大的那个值的下标,(相当于插入点)


```
import java.util.Arrays;
class CustomBinarySearch {
public static int findLeftBound(int[] arr, int target) {
int low = 0;
int high = arr.length;
while (low < high) {
int mid = low + (high - low) / 2;
if (arr[mid] < target) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
public static int findRightBound(int[] arr, int target) {
int low = 0;
int high = arr.length;
while (low < high) {
int mid = low + (high - low) / 2;
if (arr[mid] == target) {
low = mid;
}
if (arr[mid] < target) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
public static void main(String[] args) {
int[] arr = { 0, 2, 2, 2, 3, 4, 5 };
int target = 6;
int leftBound = findLeftBound(arr, target);
int rightBound = findRightBound(arr, target);
System.out.println("Left Bound Index: " + leftBound);
System.out.println("Right Bound Index: " + rightBound);
}
}
```


调用库现成。

```
import java.util.Arrays;
public class BinarySearchExample {
public static void main(String[] args) {
int[] arr = {2, 3, 4, 10, 40};
int key = 10;
int result = Arrays.binarySearch(arr, key); //如果Arrays.binarySearch()方法未找到目标元素,它将返回一个负数值。具体来说,如果目标元素不在数组中,则返回的负数值为 -(insertion point) - 1。插入点是指在数组中应该插入目标元素的索引位置,以保持数组的排序顺序。
if (result >= 0) {
System.out.println("Element found at index " + result);
} else {
int insertionPoint = -(result + 1);
if (insertionPoint < arr.length && arr[insertionPoint] == key) {
System.out.println("Element found at index " + insertionPoint);
} else {
System.out.println("Element not found in the array");
System.out.println("Insertion point is at index " + insertionPoint);
if (insertionPoint < arr.length) {
System.out.println("Next greater element is at index " + insertionPoint + ", value: " + arr[insertionPoint]);
}
}
}
}
}
```
79 changes: 79 additions & 0 deletions 二分/ZJ8 用户喜好.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import java.util.Scanner;
import java.util.Arrays;

class CustomBinarySearch {
public static int findLeftBound(int[] arr, int target) {
int low = 0;
int high = arr.length;

while (low < high) {
int mid = low + (high - low) / 2;
if (arr[mid] < target) {
low = mid + 1;
} else {
high = mid;
}
}

return low;
}

public static int findRightBound(int[] arr, int target) {
int low = 0;
int high = arr.length;

while (low < high) {
int mid = low + (high - low) / 2;
if (arr[mid] == target) {
low = mid;
}
if (arr[mid] < target) {
low = mid + 1;
} else {
high = mid;
}
}

return low;
}
}

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] nums = new int[n];
for (int i = 0; i < nums.length; i++) {
nums[i] = in.nextInt();
}
int k = in.nextInt();
for (int i = 0; i < k; i++) {
int left = in.nextInt();
int right = in.nextInt();
int target = in.nextInt();
int l1 = CustomBinarySearch.findLeftBound(nums, target);
int r1 = CustomBinarySearch.findRightBound(nums, target);
// 没有target, 或者不在区间
if (nums[l1] != target || l1 > right || r1 < left) {
System.out.println(0);
continue;
}

// 完全是子区间
if (l1 >= left && r1 <= right) {
System.out.println(r1 - l1 + 1);
continue;
} else { // 有交接
if (l1 > left) {
System.out.println(right - l1 + 1);
} else {
System.out.println(r1 - left + 1);
}
}

// 半个

}
}
}
Loading

0 comments on commit 9598430

Please sign in to comment.