Java学习笔记(三)持续更新ing

本文介绍了Java中数组的三种定义方式,包括初始化和不初始化,以及数组长度获取、元素访问和赋值的方法。随后探讨了动态规划算法的基本概念,以求解最长公共子序列和子段和问题为例,展示了动态规划的求解步骤。

数组

三种数组定义的方式

int[] array = {1,2,3,4,5,6};

int[] array2 = new int[3];

int[] array3 = new int[]{1,2,3,4,5,6};

第一种:

int[] array = {1,2,3,4,5,6};定义一个数组且初始化 

虽然没写new,但实际上也是一个对象

注:

int[10] array =  {1,2,3,4,5,6};写法错误,int[] 属于类型,中括号里面不能加任何的数字,相当于在这里破坏了它的类型。

第二种:

int[] array2 = new int[3];定义数组未初始化

第三种:

int[] array3 = new int[]{1,2,3,4,5,6};定义且初始化 

数组的使用

求数组长度:array.length

 访问数组元素:array[i]           //i为该元素索引下标

越界访问数组元素array[-1]报错:ArrayIndexOutOfBoundsException:-1

更改数组元素:array[i] = n

数组赋值的三种方法

第一种

逐个赋值:可以通过索引来逐个给数组元素赋值。例如,对于一个整型数组arr,可以使用以下方式给数组元素赋值:

arr[0] = 1;

arr[1] = 2;

arr[2] = 3;

第二种

使用循环赋值:如果需要给数组中的多个元素赋相同的值或者根据某种规律赋值,可以使用循环结构来简化代码。例如,可以使用for循环来给整型数组arr赋值:

for (int i = 0; i < arr.length; i++) {

arr[i] = i + 1;

上述代码将数组元素赋值为索引值加1,即arr[0]赋值为1,arr[1]赋值为2,以此类推。

第三种

使用数组初始化器赋值:在声明数组时可以使用数组初始化器来给数组元素赋值。例如,可以使用以下方式给整型数组arr赋值:

int[] arr = {1, 2, 3};

上述代码将数组arr的元素分别赋值为1、2、3。

实例:

例题1:通过键盘输入n个数字,并保存到数组

import java.util.Arrays;
import java.util.Scanner;
 
public class Test {
    public static void main(String[] args) {
        try(Scanner input = new Scanner(System.in)){
            System.out.println("请输入数组长度:");
            int n = input.nextInt();
            System.out.println("请输入数:");
            //创建数组
            int[] numbers = new int[n];
            //循环输入n个数字,并保存到数组numbers
            for(int i = 0;i < n;i++) {
                numbers[i] = input.nextInt();
                System.out.println(Arrays.toString(numbers));
            }
        }
    }
}

动态规划算法

通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划算法通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决。

动态规划对于子问题重叠的情况特别有效,因为它将子问题的解保存在表格中,当需要某个子问题的解时,直接取值即可,从而避免重复计算。

适用问题及求解步骤

适合用动态规划来解决的问题,都具有下面三个特点:最优化原理、无后效性、有重叠子问题。

(1)最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。

(2)无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。

(3)有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势。

求解步骤通常是:初始状态→│决策1│→│决策2│→…→│决策n│→结束状态。具体包括以下几步:

(1)划分:按照问题的特征,把问题分为若干阶段。注意:划分后的阶段一定是有序的或者可排序的。

(2)确定状态和状态变量:将问题发展到各个阶段时所处的各种不同的客观情况表现出来。状态的选择要满足无后续性。

(3)确定决策并写出状态转移方程:状态转移就是根据上一阶段的决策和状态来导出本阶段的状态。根据相邻两个阶段状态之间的联系来确定决策方法和状态转移方程。

(4)边界条件:状态转移方程是一个递推式,因此需要找到递推终止的条件。

实例:

例题1:

题目描述

使用动态规划算法求两个序列的最长公共子序列,需构造一条最长公共子序列。

输入

每组输入包括两行,每行包括一个字符串。

输出

两个字符序列的一条最长公共子序列。(输入已确保最长公共子序列的唯一性)

import java.util.Scanner;

public class Main {

        public static void main(String[] args) {

                Scanner sc = new Scanner(System.in);

                // 读取两个字符串

                String a = sc.nextLine();

                String b = sc.nextLine();

                // 获取字符串长度

                int m = a.length();

                int n = b.length();

                // 创建二维DP表

                int[][] dp = new int[m + 1][n + 1];

                // 填充DP表

                for (int i = 1; i <= m; i++) {

                        for (int j = 1; j <= n; j++) {

                                if (a.charAt(i - 1) == b.charAt(j - 1)) {

                                        // 如果字符相同,则长度+1

                                        dp[i][j] = dp[i - 1][j - 1] + 1;

                                        } else {

                                        // 否则取两者中的较大值

                                        dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);

                                        }

                                }

                        }

                        // 从DP表回溯,构造最长公共子序列

                        StringBuilder lcs = new StringBuilder();

                        int i = m;

                        int j = n;

                        while (i > 0 && j > 0) {

                                if (a.charAt(i - 1) == b.charAt(j - 1)) {

                                        // 如果字符相同,添加到结果中

                                        lcs.append(a.charAt(i - 1));

                                        i--;

                                        j--;

                                } else if (dp[i - 1][j] > dp[i][j - 1]) {

                                        // 选择dp[i-1][j]较大的值

                                        i--;

                                } else {

                                        // 选择dp[i][j-1]较大的值

                                        j--;

                                }

                        }

                        // 反转lcs得到正确的顺序

                        lcs.reverse();

                        // 输出最长公共子序列

                        System.out.println(lcs.toString());

                        }

                }

实例练习:

例题1:

题目描述

给定n个整数(可能是负数)组成的序列a[1], a[2], a[3], …, a[n],求该序列的子段和如a[i]+a[i+1]+…+a[j]的最大值。

输入

每组输入包括两行,第一行为序列长度n,第二行为序列。

输出

输出字段和的最大值。

import java.util.Scanner;

public class Main {

        public static void main(String[] args) {

                // TODO Auto-generated method stub

                Scanner sc = new Scanner(System.in);

                //System.out.println("输入一个正整数:");

                int n = sc.nextInt();

                //System.out.println(n);

                int[] a = new int [n];

                Scanner in = new Scanner(System.in);

                //System.out.println("输入n个整数:");

                for(int i = 0;i < n;i++) {

                        a[i] = in.nextInt();

                        //System.out.println(a[i]);

                }

                if(n==1) {

                        System.out.println(a[0]);

                }else {

                        int[] sum = new int [n];

                        sum[0] = a[0];

                        int maxSum = sum[0];

                        for(int i = 1;i < n;i++) {

                                sum[i] = Math.max(a[i], sum[i-1]+a[i]);

                                maxSum = Math.max(maxSum,sum[i]);

                        }

                        System.out.println (maxSum);

                }

        }

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值