4.01 数组概述和定义格式说明
数组是用来存储固定大小的同类型元素。是同一种类型数据的集合,本身为一个容器
好处:方便操作数据元素,数组中的数据元素
定义数组:
定义格式
数据类型 [] 变量名=new 数据类型[长度];
例: int [] array=new int [5];
分析数组:
左边:
int:数据类型(基本数据类型/引用数据类型)
[]:定义的数组类型
array:变量名
int [] array也可以定义成:int array[]
右边:
new int [5];
new:创建数组对象的关键字
int[5]:数组最多可以存放多少数据元素
** 数组相关数据类型默认值:
int 0
double 0.0
blooean flase
处理数组
数组的元素类型和数组的大小都是确定的,所以当处理数组元素时候,我们通常使用基本循环。
4.02 数组的初始化动态初始化
Java中的数组必须先初始化,然后才能使用。
所谓初始化,就是为数组中的数组元素分配内存空间,并为每个数组元素赋值
动态初始化:(由系统分配初始值)
数据类型 [] 变量名=new 数据类型[长度];
变量名[0]=值;
...
静态初始化:
(1)直接赋值
(2)遍历数组赋值
for(初始值;判断条件;i++){
//赋值
}
(3)把已有的的数组的引用赋值给新创建的数组。
4.03 Java中内存分配以及栈和堆的区别
Java程序在运行时,需要在内存中分配空间。为了提高运算效率,有对空间进行了不同区域划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
栈
堆
方法区
本地方法区
寄存器
例子:
class ArrayDemo1{
public static void main(String[] args){
int[] arr=new int[10]; //创建一个数组
System.out.println(arr[0]);
int[] arr2=arr; //给新数组赋值
arr2[0]=888; //数组元素赋值
System.out.println(arr[0]); //888
arr=null; //值置空
arr2=null;
System.out.println(arr[0]);
//报错 NullPointerException 引用变量找到不对象:要么压根没创建对象 要么本身是null
//当一个对象没有被任何变量所引用的时候 则成为垃圾
//垃圾有Java中垃圾回收机制处理 C/C++-free()函数
}
}
执行流程:
4.04 数组操作的两个常见小问题越界和空指针
ArrayIndexOutofBoundsException 数组角标越界异常
是指数组中没有合格角标
NullPointerException 空指针异常
引用变量找到不对象:要么压根没创建对象 要么本身是null
4.05 数组的基本操作
-
遍历数组
for循环遍历数组
for(int i=0;i<数组.length;i++){ }
-
获取数组中最大和最小值
int[] arr=new int[]{1,2,3,4,5};
int max=arr[0];
int min=arr[0];
for(int i=0;i<arr.length;i++){
if(arr[i]>max){
max=arr[i];
}
if(arr[i]<min){
min=arr[i];
}
}
- 将数组元素逆序输出
for(int i=arr.length-1;i>=0;i--){
System.out.println(arr[i]);
}
arr=new int[]{1,2,3,4,5,6,7,8,9,10};
for(int i=0;i<arr.length/2;i++){
/*
arr[i]=arr[i]^arr[arr.length-i-1]; //两数交换 方法一
arr[arr.length-i-1]=arr[i]^arr[arr.length-i-1];
arr[i]=arr[i]^arr[arr.length-i-1];
*/
/*
int a=3; 两数交换 方法二
int b=7;
a=a+b; //10
b=a-b; //10-7 3
a=a-b; //10-3 7
*/
/*
int temp=arr[i]; //两数交换 方法三
arr[i]=arr[arr.length-1-i];
arr[arr.length-1-i]=temp;
*/
}
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
-
数组元素查找
①顺序查找
for(int i=0;i<arr.length;i++){
if(arr[i]==要找的数){
break;
}
}
②二分查找(前提是数组有序)
int min=0;
int max=arr.length-1;
int mid=(min+max)/2;
int key=要找的数;
while(arr[mid]!=key){
if(arr[mid]>key){
max=mid-1;
}
if(arr[mid]<key){
min=mid+1;
}
mid=(min+max)/2;
if(min>max){
mid=-1;
break;
}
}
System.out.println(mid);
5. 数组元素排序
//插入排序
public static void insertSort(){
int[] arr=new int[10000];
for(int i=0;i<arr.length;i++){
arr[i]=(int)(Math.random()*5);
}
long start=System.currentTimeMillis();
for(int i=1;i<arr.length;i++){
int e=arr[i];
int j;
for(j=i;j>0&&arr[j-1]>e;j--){
arr[j]=arr[j-1];
}
arr[j]=e;
}
long end=System.currentTimeMillis();
System.out.println("插入排序time="+(end-start));
}
//冒泡排序
public static void bubbleSort(){
int[] arr=new int[10000];
for(int i=0;i<arr.length;i++){
arr[i]=(int)(Math.random()*5);
}
long start=System.currentTimeMillis();
for(int i=0;i<arr.length-1;i++){
for(int j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
long end=System.currentTimeMillis();
System.out.println("冒泡排序time="+(end-start));
}
//选择排序
public static void selectSort(){
int[] arr=new int[10000];
for(int i=0;i<arr.length;i++){
arr[i]=(int)(Math.random()*5);
}
long start=System.currentTimeMillis();
for(int i=0;i<arr.length-1;i++){ //-1 最后一个数字没必要参与比较
for(int j=i+1;j<arr.length;j++){
if(arr[i]>arr[j]){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
}
long end=System.currentTimeMillis();
System.out.println("选择排序time="+(end-start));
}
6. 数组扩容问题
数组一旦创建 其容量不可改变
直接不行就间接 重新创建一个数组
把原先数组里的元素赋值到新数组中
将新数组的地址赋予原先的变量
import java.util.Arrays;
class ArrayCopyDemo{
public static void main(String[] args){
int[] arr=new int[]{1,2,3,4,5};
arr=arrayCopy(arr,arr.length+1);
arr[5]=6;
System.out.println(arrayToString(arr));
}
public static int[] arrayCopy(int[] arr,int newLength){
int[] newArr=new int[newLength]; //[1,2,3,4,5,0]
for(int i=0;i<arr.length;i++){
newArr[i]=arr[i];
}
return newArr;
}
8.经典例题:
- (计算数字的出现次数)编写程序,读取在1到100之间的整数,然后计算每个数出现的次数。段定输人是以0结束的。
import java.util.*;
class Demo4_10{
public static void main(String[] args){
resolve1();
}
public static void resolve1(){ //解法一
int[] nums=new int[100];
Scanner scanner=new Scanner(System.in);
System.out.print("Enter the integers :");
while(true){
int num=scanner.nextInt();
if(num==0){ //以0结尾
break;
}else{
nums[num-1]++; //例:如果数字4进入数组,将下标为4-1位置的元素+1,实际上元素四没有进入数组。
}
}
for(int i=0;i<nums.length;i++){ //循环输出元素下标+1,和次数下标相对应的元素
if(nums[i]!=0){
if(nums[i]==1){
System.out.println(i+1+" occurs "+1+" time ");
}else{
System.out.println(i+1+" occurs "+nums[i]+" times ");
}
}
}
}
}
import java.util.*;
class Demo4_10{
public static void main(String[] args){
resolve2();
}
public static void resolve2(){ //解法二
int[] nums=new int[0];
Scanner scanner=new Scanner(System.in);
System.out.print("Enter the integers :");
while(true){
int num=scanner.nextInt();
if(num==0){
break;
}
nums=Arrays.copyOf(nums,nums.length+1); //扩容
nums[nums.length-1]=num;
}
insertSort(nums);
for(int i=0;i<nums.length;){ //计数
int count=1;
for(int j=i+1;j<nums.length;j++){
if(nums[i]==nums[j]){
count++;
}else{
break;
}
}
if(count==1){
System.out.println(nums[i]+" occurs "+1+" time");
}else{
System.out.println(nums[i]+" occurs "+count+" times");
}
i=i+count;
}
}
public static void insertSort(int[] arr){ //插入排序
for(int i=1;i<arr.length;i++){
int e=arr[i];
int j;
for(j=i;j>0&&arr[j-1]>e;j--){
arr[j]=arr[j-1];
}
arr[j]=e;
}
}
}
解题思路:
第一种解:(元素没有进入数组,利用下标进行标记)
-
直接创建长度为100的数组
-
输入一个数字,将该数字作为角标对应到数组中 然后相应元素+1
直到输入0结束 -
然后在遍历数组
相应元素为0 不管 -
输出时
1 time
>1 times
第二种解:(先排序 进行遍历看有几个连续相等 )
例2 2 2 3 4 4 4 4 4 5 5 6 6 7
- 实例化一个长度为0数组,进入一个元素进行一次扩容。
- 代码给出的是插入排序。(也可以使用冒泡排序,选择排序,详细见前面的三种排序方式)
- 遍历整个数组,计数出相同元素出现的次数
- 打印输出
-
(游戏:豆机)豆机,也称为梅花瓶或高尔顿瓶,它是一个用来做统计实验的设备,是用英国科学家瑟弗兰克斯高尔顿的名字来命名的。它是-一个三角形状的均匀放置钉子(或钩子)的直立板子。
球都是从板子口落下的。每当球碰到钉子,它就有50%的机会落向左边或落向右边。在板子底部的槽子中都会累积一堆球。编写程序模拟豆机。程序应该提示用户输人球的个数以及机器的槽数。打印每个球的路径模拟它的下落。例如:在图7-13b中球的路径是LLRRLLR,而在图7-13c中球的路径是RLRRLRR。使用条形图显示槽中球的最终储备量。
import java.util.*;
class Demo4_13{
public static void main(String[] args){
Scanner scanner=new Scanner(System.in);
System.out.print("Enter the number of balls to drop:");
int ballsCount=scanner.nextInt(); //球的个数
System.out.print("Enter the number of slots in the bean machine:");
int slotsCount=scanner.nextInt(); //槽子的个数
String[] paths=new String[ballsCount];//球的路径数组
int[] slots=new int[slotsCount]; //槽子数组
for(int i=0;i<ballsCount;i++){ //分别模拟每一个球的路径
String path="";
for(int j=0;j<slotsCount-1;j++){ //每一个球所经历的钉子
if((int)(Math.random()*2)==0){ //左
path+="L";
}else{ //右
path+="R";
}
}
paths[i]=path; //路径
}
for(int i=0;i<paths.length;i++){ //打印输出路径
System.out.println(paths[i]);
}
for(int i=0;i<paths.length;i++){ //计数R的个数
String path=paths[i];
int count=0;
for(int j=0;j<path.length();j++){
if(path.charAt(j)=='R'){
count++;
}
}
slots[count]++;
}
for(int i=0;i<slots.length;i++){ //打印输出
System.out.println("第"+(i+1)+"个槽子:"+slots[i]);
}
}
}
解题思路:
- 提示用户输入球的个数
- 提示用户输入槽子的个数-1—>钉子的排数
- 模拟每个球的路径 for循环
在碰到每个钉子for循环
随机的生成两个数代表走左边/走右边 - 统计每个路径中R的个数
- 创立一维数组来接收槽子的球数
以R的个数作为数组的下标,小球落入相应下标的元素+1 - 打印输出小球路径和槽子的小球个数
3.(游戏:储物柜难题)一个学校有100个储物柜和100个学生。所有的储物柜在上学第一天都是关着的。随着学生进来,第一个学生(用S1表示)打开每个柜子。然后,第二个学生(用S2表示)从第二个柜子(用L2表示)开始,关闭相隔为1的柜子。学生S3从第三个柜子开始,然后改变每个第三个柜子(如果它是开的就关上,如果它是关的就打开)。学生S4从柜子L4开始,然后改变每个第四个柜子的开闭状态。学生S5从L5开始,然后改变每个第五个柜子的状态,依此类推,直到学生S100改变L100为止。
在所有学生都经过教学楼并且改变了柜子之后,哪些柜子是开的?编写程序找出答案。
import java.util.Scanner;
class Demo4_14{
public static void main(String[] args){
Scanner scanner=new Scanner(System.in);
System.out.print("输入学生的个数:");
int count=scanner.nextInt(); //学生的人数
boolean[] status=new boolean[20]; //储物柜当前的状态
for(int i=0;i<count;i++){ //从第1~第100个学生
for(int j=i;j<20;){
status[j]=!status[j];
j+=i+1; //j=i+i+1
}
}
for(int i=0;i<status.length;i++){ //打印输出
String s=status[i]==true?"开":"关";
System.out.print(s+" ");
}
}
}
解题思路:
(1)定义一个布尔数组表示当前柜子的开关状态
(2)每个学生for循环 步长为1
改变柜子的状态for循环 步长为 当前柜子数+当前人数
(3)打印输出各个柜子的开关状态
- 给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在众数。
class LeetCode169{
public static void main(String[] args){
System.out.print(majorityElement(nums));
}
public static int majorityElement(int[] nums) { //方法一
int maj=nums[0];
int count=1;
for(int i=1;i<nums.length;i++){
if(nums[i]==maj){
count++;
}else{
count--;
if(count==0){
maj=nums[i];
count=1;
}
}
}
return maj;
}
}
class LeetCode169{
public static void main(String[] args){
System.out.print(majorityElement(nums));
}
public static int majorityElement(int[] nums) { //方法二
Arrays.sort(nums); //排序
int maxCount=0; //计数
int majority=0; //留下的数字
for(int i=0;i<nums.length;){
int count=1;
for(int j=i+1;j<nums.length;j++){
if(nums[i]==nums[j]){ //比较两数
count++;
}else{
break;
}
}
if(count>maxCount){
maxCount=count;
majority=nums[i];
}
i+=count;
if(i>nums.length/2){
break;
}
}
return majority;
}
解题思路:
方法一:
对数组进行排序--->遍历数组,计数找出出现最多的那个。
方法二:
元素相消的方法,最后留下的就是众数
(1)随便取出第一个元素,计数计做1,再取出第二个元素。
计数为1时:
两个进行比较,如果 相同--->计数+1
不相等---->去掉第一个元素,计数计第二个元素
计数大于1时 如果 相同----->计数+1
不相同----->计数-1,第二个元素消去
(2)以此方法全部消除完,留下的是众数。
5.在《英雄联盟》的世界中,有一个叫 “提莫” 的英雄,他的攻击可以让敌方英雄艾希(编者注:寒冰射手)进入中毒状态。现在,给出提莫对艾希的攻击时间序列和提莫攻击的中毒持续时间,你需要输出艾希的中毒状态总时长。
你可以认为提莫在给定的时间点进行攻击,并立即使艾希处于中毒状态。
class LeetCode495{
public static void main(String[] args){
System.out.print(findPoisonedDuration(timeSeries, duration));
}
public static int findPoisonedDuration(int[] timeSeries, int duration) { //中毒数组 持续时间
if(timeSeries==null||timeSeries.length==0){
return 0;
}
int total=0;
for(int i=0;i<timeSeries.length-1;i++){
int delt=timeSeries[i+1]-timeSeries[i];
if(delt>duration){ //判断两击中点之间的时间
total+=duration;
}else{
total+=delt;
}
}
total+=duration;
return total;
}
}
解题思路:
中毒点 持续时间 中毒总时间
[1,4,7] 2 2+2+2=6
[1,3,5] 3 2+2+3=7
如果时间差大于中毒时间 满毒时间
如果时间差小于等于中毒事件 时间差
最后一秒直接+满毒时间
6.给定一个非负整数数组 A,返回一个由 A 的所有偶数元素组成的数组,后面跟 A 的所有奇数元素。你可以返回满足此条件的任何数组作为答案。
import java.util.Arrays;
class LeetCode905{
public static void main(String[] args){
int[] A={1,2,3,4,5,6,7,8,9};
A=sortArrayByParity(A);
System.out.println(Arrays.toString(A));
}
public static int[] sortArrayByParity(int[] A) { //方法一
if(A==null){
return null;
}
for(int i=1;i<A.length;i++){
if(A[i]%2==0){
int e=A[i];
int;
for(j=i;j>0&&A[j-1]%2==1;j--){
A[j]=A[j-1];
}
A[j]=e;
}
}
return A;
}
}
import java.util.Arrays;
class LeetCode905{
public static void main(String[] args){
int[] A={1,2,3,4,5,6,7,8,9};
A=sortArrayByParity(A);
System.out.println(Arrays.toString(A));
}
static int[] sortArrayByParity(int[] A) { //方法二
if(A==null){
return null;
}
int start=0;
int end=A.length-1;
while(start<end){
if(A[start]%2==0&&A[end]%2==0){
start++;
}else if(A[start]%2==0&&A[end]%2==1){
start++;
end--;
}else if(A[start]%2==1&&A[end]%2==0){
int temp=A[start];
A[start]=A[end];
A[end]=temp;
}else{
end--;
}
}
return A;
}
}
import java.util.Arrays;
class LeetCode905{
public static void main(String[] args){
int[] A={1,2,3,4,5,6,7,8,9};
A=sortArrayByParity(A);
System.out.println(Arrays.toString(A));
}
public static int[] sortArrayByParity(int[] A) { //方法三
if(A==null){
return null;
}
for(int i=0;i<A.length-1;i++){
if(A[i]%2==9){
continue;
}
for(int j=i+1;j<A.length;j++){
if(A[j]%2==0){
int temp=A[j];
A[j]=A[i];
A[i]=temp;
break;
}
}
}
return A;
}
}
解题思路:
三种方法:
(1)插入排序思想
详情见排序方法中的插入排序。唯一不同的是判断条件从小到大---->从偶到奇
(2)夹逼思想
(3)选择排序思想
详细步骤见前面排序的三种方法之选择排序,唯一不同的是条件改为偶数每次插在数组的第一个位置上。