目录
问题:把这些变量类中,和放到成员方法中的区别,对结果产生的影响
最大子列和问题
算法一 :T(N) = O(N^3);
import java.util.Scanner;
public class Test1 {
public static void main(String[] args) {
//键盘录入,序列元素个数和元素
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
//定义一个一维数组
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
//定义变量,thisSum, maxSum,分别记录,当前子列和 , 最大子列和
int thisSum ,maxSum = 0;
for(int i = 0; i < n; i++){ //i是子列左端位置
for (int j = i; j < n; j++) { //j是子列右端位置
thisSum = 0; //thisSum是从arr[i]到arr[j]的子列和
for (int k = i; k < j; k++) {
thisSum += arr[k];
if (thisSum > maxSum) { //如果刚得到的这个子列和更大
maxSum = thisSum; //则结果更新
}
}
}
}
System.out.println(maxSum);
}
}
算法二 : T(N) = O(N^2);
import java.util.Scanner;
public class Test2 {
public static void main(String[] args) {
//键盘录入,序列元素个数和元素
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
//定义一个一维数组
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
//定义变量,thisSum, maxSum,分别记录,当前子列和 , 最大子列和
int thisSum ,maxSum = 0;
for(int i = 0; i < n; i++){ //i是子列左端位置
thisSum = 0; //thisSum是从arr[i]到arr[j]的子列和
for (int j = i; j < n; j++) { //j是子列右端位置
thisSum += arr[j];
//对于不同的i,不同的j,只要在j - 1次循环的基础上累加一项即可
if (thisSum > maxSum) { //如果刚得到的这个子列和更大
maxSum = thisSum; //则结果更新
}
}
}
System.out.println(maxSum);
}
}
算法三 : 分而治之
分而治之(Divide and Conquer)是一种算法设计思想,它将一个大问题划分为多个相互独立且结构相似的子问题,递归地解决这些子问题,最后将子问题的结果合并起来得到原问题的解。该思想常用于解决一些复杂的问题,可以提高算法的效率和可读性。
import java.util.List;
import java.util.Scanner;
//分治法求List[left]到List[right]的最大子列和
class DivideAndConquer{
public DivideAndConquer() {
}
public int max(int a, int b, int c){
return a > b ? Math.max(a, c) : Math.max(b, c);
}
public int divideAndConquer(int[] List, int left, int right) {
int maxLeftSum, maxRightSum; //存放左右子问题的解
int maxLeftBorderSum, maxRightBorderSum; //存放跨分界线的结果
int leftBorderSum, rightBorderSum;
int center;
if(left == right) { //递归的终止条件,子列只有1个数字
return Math.max(List[left], 0);
}
//下面是"分"的过程
//1. 找到中分点
center = (left + right)/ 2;
//2.递归求得两边子列的最大和
maxLeftSum= divideAndConquer(List,left,center);
maxRightSum = divideAndConquer(List,(center + 1), right);
//下面求跨分界线的最大子列和
maxLeftBorderSum = 0;
leftBorderSum = 0;
for (int i = center; i >= left; i--) { //从中线左边扫描
leftBorderSum += List[i];
if(leftBorderSum > maxLeftBorderSum) {
maxLeftBorderSum = leftBorderSum;
}
}
maxRightBorderSum = 0;
rightBorderSum = 0;
for (int i = center + 1; i <= right; i++) { //从中线右边边扫描
rightBorderSum += List[i];
if(rightBorderSum > maxRightBorderSum) {
maxRightBorderSum = rightBorderSum;
}
}
//下面返回"治"的结果;
return max(maxLeftSum, rightBorderSum, (maxLeftBorderSum + maxRightBorderSum));
}
}
public class Test3 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
//定义一个一维数组
int[] List = new int[n];
for (int i = 0; i < n; i++) {
List[i] = sc.nextInt();
}
DivideAndConquer d = new DivideAndConquer();
System.out.println(d.divideAndConquer(List,0,n - 1));
}
}
问题:把这些变量类中,和放到成员方法中的区别,对结果产生的影响
对于变量的类中和成员方法中的区别:
类中的变量:类中的变量是该类的成员变量,它们被所有方法所共享,可以被类的任何方法访问和修改。这意味着类中的变量的作用范围更广,可以在多个方法中使用,并且其值可以保持状态。
方法中的变量:方法中的变量是局部变量,它们只在方法的作用域范围内有效。方法中的变量在方法执行完毕后会被销毁,不会保留其状态。
对结果产生的影响:
将变量放到成员方法中会对结果产生影响,因为成员方法中的变量是共享的,可以在多个方法之间传递和修改值。这意味着在分而治之的过程中,可以通过成员方法中的变量来共享中间结果,从而优化算法的执行效率。
而将变量放到类中,可以在多个方法调用之间保持变量的状态,避免了重复计算,提高了代码的可读性和性能。
总之,将变量放到类中可以更方便地在不同的方法之间共享和保持变量的状态,而将变量放到成员方法中可以灵活地传递和修改变量的值,在分而治之的过程中,这样的设计可以更好地利用中间结果,提高算法的效率。
算法四 : 在线处理( T(N) = O(N) );
“在线”的意思是指每输入一个数据就进行即时处理,在任何一个地方中止输入,算法都能正确给出当前的解。
import java.util.Scanner;
public class Test4 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
//定义一个一维数组
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
//定义变量,thisSum, maxSum,分别记录,当前子列和 , 最大子列和
int thisSum = 0, maxSum = 0;
for(int i = 0; i < n; i++){
thisSum += arr[i]; //向右累加
if(thisSum > maxSum) { //发现更大和则更新当前结果
maxSum = thisSum;
}else if(thisSum < 0){ //如果当前子数列和为负
thisSum = 0; //则不可能使后面的部分和增大
}
}
System.out.println(maxSum);
}
}
变量未初始化的错误通常是因为在声明变量后没有给其赋初始值。在Java中,所有的变量都必须先初始化后才能使用。如果没有给变量赋值,那么编译器就会报错。
为什么要初始化
避免使用未初始化的变量导致的错误: 当一个变量没有初始化时,它的值是不确定的。如果在使用未初始化的变量时,可能会导致程序出现意外的行为,例如产生错误的计算结果、引发异常等。为了避免这种情况,Java要求在使用变量之前进行初始化,以确保变量具有一个明确的初始值。
强制变量的显式初始化: Java是一门强类型语言,要求变量在使用之前需要进行明确的类型赋值。通过要求变量进行显式初始化,可以确保变量的类型和值的一致性。这有助于提前发现编程错误,避免潜在的类型不匹配问题。
提高代码的可读性和可维护性: 初始化变量可以提高代码的可读性和可维护性。通过显式初始化,可以清晰地表达变量的初始值,使代码更易于理解和调试。此外,初始化变量还可以避免在后续的代码中出现意外的错误,减少了代码维护的难度。
需要注意的是,Java中的变量初始化并不仅仅是简单地给变量赋一个初值。对于成员变量和实例变量,Java会自动为其提供默认值;而对于局部变量,Java要求在使用之前进行显式初始化。此外,对于引用类型的变量,初始化的过程包括分配内存空间和调用构造方法。