第一题:集合的运用(幸存者)
public class demo1 {
public static void main(String[] args) {
ArrayList<Integer> array = new ArrayList<>(); //一百个囚犯存放在array集合中
Random r = new Random();
for (int i = 0; i < 100; i++) {
OUT:
while (true) {
int n = r.nextInt(200)+1; //生成随机数1-200
//用for循环对比有没有重复比较复杂
// for (int j = 0; j < i; j++) {
// if(n==array.get(j)){ //随机数重复
// continue OUT;
// }
// }
if(array.contains(n)){ //随机数重复
continue OUT;
}
//说明没有重复的
array.add(n);
break OUT;
}
}
System.out.println(array);
ArrayList<Integer> arr = new ArrayList<>(); //保存一百个囚犯第一次的存放位置
arr.addAll(array);
System.out.println(arr);
//题中要求位置从1开始计数,现在我们的位置是从0开始,所以后续计算要+1
while(array.size()>1){
for (int i = array.size()-1; i>=0; i--) {
if((i+1)%2==1){ //奇数位置
array.remove(i);
}
}
System.out.println(array);
}
System.out.println("幸存者编号:" + array.get(0));
System.out.print("幸存者第一次所占的位置(从1开始算):");
System.out.print(arr.indexOf(array.get(0)) + 1);
}
}
第二题:基础编程能力
//User
public class User {
private Long id; //用户id
private String name; //用户名
private String gender; //用户性别
private LocalDate birthday; //用户生日
public User() {
}
public User(Long id, String name, String gender, LocalDate birthday) {
this.id = id;
this.name = name;
this.gender = gender;
this.birthday = birthday;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public LocalDate getBirthday() {
return birthday;
}
public void setBirthday(LocalDate birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", gender='" + gender + '\'' +
", birthday=" + birthday +
'}';
}
}
//demo2
public class demo2 {
public static void main(String[] args) {
//创建一个ArrayList集合
List<User> users = new ArrayList<>();
//解析字符串
String userStrs = "10001:张三:男:1990-01-01#10002:李四:女:1989-01-09#10003:王五:男:1999-09-09#10004:刘备:男:1899-01-01#10005:孙悟空:男:1900-01-01#10006:张三:女:1999-01-01#10007:刘备:女:1999-01-01#10008:张三:女:2003-07-01#10009:猪八戒:男:1900-01-01";
String[] strs = userStrs.split("#"); //用#号把每个用户的数据先拆分开
//System.out.println(Arrays.toString(strs)); //[10001:张三:男:1990-01-01, 10002:李四:女:1989-01-09, 10003:王五:男:1999-09-09, 10004:刘备:男:1899-01-01, 10005:孙悟空:男:1900-01-01, 10006:张三:女:1999-01-01, 10007:刘备:女:1999-01-01, 10008:张三:女:2003-07-01, 10009:猪八戒:男:1900-01-01]
for (int i = 0; i < strs.length; i++) {
String s = strs[i];
String[] str2 = s.split(":"); //用:号把每个用户的个人数据(id 姓名 性别 生日)拆分开
//str2[0]代表id str2[1]代表姓名 str2[2]代表性别 str2[3]代表生日
long id = Long.parseLong(str2[0]); //把用户id从String型转换成long型
//long id = Long.valueOf(str2[0]); //把用户id从String型转换成long型
//把生日转换成从字符串转换成LocalDate
LocalDate birth = LocalDate.parse(str2[3]);
// String[] time = str2[3].split("-"); //time[0]代表年 time[1]代表月 time[2]代表日
// int year = Integer.parseInt(time[0]);
// int month = Integer.parseInt(time[1]);
// int day = Integer.parseInt(time[2]);
// LocalDate birth = LocalDate.of(year,month,day);
User user = new User(id,str2[1],str2[2],birth);
users.add(user);
}
System.out.println(users);
System.out.println("============================================");
//遍历List<User>集合,统计每个名字出现的次数
Map<String,Integer> map = new HashMap<>();
for (int i = 0; i < users.size(); i++) {
User user = users.get(i);
if(map.containsKey(user.getName())){ //如果用户的名字在map的键中存在
map.put(user.getName(),map.get(user.getName())+1);
}else{ //如果用户的名字在map的键中第一次出现
map.put(user.getName(),1);
}
}
//System.out.println(map);
map.forEach((k,v) -> System.out.println(k+":"+v+"次"));
}
}
第三题:JDK8新时间的应用
public class demo3 {
public static void main(String[] args) {
LocalDate ld = LocalDate.of(2022,2,3); //记录首次休息日
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入您查询月份(XXXX-X):");
String s = sc.next();
if(!s.matches("\\d{4}-\\d{1,2}")){
System.out.println("您输入的时间格式不正确,请重新输入");
continue;
}else {
String[] str = s.split("-");
int year = Integer.parseInt(str[0]); //查询的年份
int month = Integer.parseInt(str[1]); //查询的月份呢
if(month > 12 || month < 1){ //查询的月份不是1-12之间
System.out.println("请输入正确的月份(1-12)~~~");
}else if (year < 2022 || (year == 22 && month <= 2)) { //查询月份不在2022年2月之后
System.out.println("请输入2022年2月之后的月份~~~");
} else { //查询月份在2022年2月之后 且 月份符合规范(1-12)
int days = dayNum(year, month); //该月有几天
//打印该月的上班情况
for (int i = 1; i < days; i++) {
LocalDate date = LocalDate.of(year, month, i);
//判断该日是否是休息日
Long next = date.toEpochDay() - ld.toEpochDay(); //获取相差天数
if (next % 3 == 0) {
System.out.print(date + "[休息]");
//判断休息日是否是周末(周六 周日)
if(date.getDayOfWeek() == DayOfWeek.SATURDAY){
System.out.print("[周六] ");
}else if(date.getDayOfWeek() == DayOfWeek.SUNDAY){
System.out.println("[周日] ");
}else{
System.out.print(" ");
}
} else if (next % 3 == 1 || next % 3 == 2) {
System.out.print(date + " ");
}
}
break;
}
}
}
}
public static int dayNum(int year, int month) {
int num = 0;
switch (month){
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
num = 31;
break;
case 4:
case 6:
case 9:
case 11:
num = 30;
break;
case 2:
if((year%4==0 && year%100!=0) || (year%400==0)){
//闰年
num = 29;
}else{
num = 28;
}
break;
default:
System.out.println("月份有误");
break;
}
return num;
}
}
第四题:手写ArrayList集合
//MyArrayList
public class MyArrayList<E> {
private Object[] arr = new Object[10];
private int count = 0; //记录数组中现存有几个数据
private double gene = 0.8; //激活因子
//往集合中添加数据(返回值是boolean类型)
public boolean add(E e){
arr[count] = e;
count++;
if(count >= arr.length * gene){
Object[] arr1 = Arrays.copyOf(arr,arr.length * 2); //如果数组中的数据个数等于或超过数组最大范围的80%,则扩容两倍
arr = arr1;
}
//System.out.println(Arrays.toString(arr));
//但是由于用户只是当成集合,应该设计成看不到最后扩容的null值位
//比如用户存入第一个数据11,用户希望返回的是[11],不是[11,null,null…]
// Object[] rs = Arrays.copyOf(arr,count);
// System.out.println(Arrays.toString(rs));
return true;
}
//根据索引查询指定元素
public E get(int index) {
//但是由于用户只是当成集合,应该设计成看不到最后扩容的null值位
//比如用户存入第一个数据11,用户希望返回的是[11],不是[11,null,null…]
//因此用户输入超过他自己存入个数的索引值,就产生了越界
if(index >= count || index < 0){ //索引值越界
throw new ArrayOutException("您输入的索引越界");
}else{
return (E) arr[index];
}
}
//根据索引删除指定元素(返回值是被删除的元素)
public E remove(int index){
if(index >= count || index < 0) { //索引值越界
throw new ArrayOutException("您输入的索引越界");
}else{
E e = (E) arr[index]; //记录被删除元素
//删除的元素是最后一个元素
if(index == arr.length-1){ //由于扩容机制,所以不会删除的元素永远不会是数组的最后一个
arr[index] = null;
return e;
}
//删除的元素不是最后一个元素,需要进行移位(后面的数前移)
for (int i = index + 1; i < arr.length; i++) {
if(i != arr.length-1){
arr[i-1] = arr[i];
}else{
arr[i] = null; //由于扩容机制,永远都没有存满,最后一位永远是null,因此最后一个数的前移不会导致最后一位多出来一个重复的数
}
}
//System.out.println(Arrays.toString(arr));
count--; //数组元素个数-1
//但是由于用户只是当成集合,应该设计成看不到最后扩容的null值位
//比如用户存入第一个数据11,用户希望返回的是[11],不是[11,null,null…]
// Object[] rs = Arrays.copyOf(arr,count);
// System.out.println(Arrays.toString(rs));
return e;
}
}
//返回集合大小
public int size(){
return count;
}
//遍历集合
public void forEach1(){
for (int i = 0; i < count; i++) {
System.out.print(arr[i]+ " ");
}
System.out.println();
}
//遍历集合(可以用Lambda表达式)
public void forEach(MyConsumer<E> action){
Objects.requireNonNull(action);
for (int i = 0; i < count; i++) {
action.accept((E) arr[i]);
}
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < count; i++) {
E e = (E) arr[i];
sb.append(e).append(i==count-1?"":", "); //判断该元素是否是最后一个数据,是否需要加,
}
sb.append("]");
return sb.toString();
}
}
//MyConsumer
public interface MyConsumer<E> {
void accept(E e);
}
//ArrayOutException
public class ArrayOutException extends RuntimeException{
public ArrayOutException(){
}
public ArrayOutException(String message){
super(message);
}
}
//demo4
public class demo4 {
public static void main(String[] args) {
MyArrayList<Integer> arr = new MyArrayList<>();
arr.add(11);
arr.add(22);
arr.add(33);
arr.add(44);
arr.add(55);
arr.add(66);
arr.add(77);
arr.add(88);
arr.add(99);
System.out.println(arr); //[11, 22, 33, 44, 55, 66, 77, 88, 99]
System.out.println(arr.size()); //集合大小 9
System.out.println(arr.get(8)); //索引8是99
//System.out.println(arr.get(11)); //您输入的索引越界
//System.out.println(arr.get(-1)); //您输入的索引越界
System.out.println(arr.remove(7)); //返回被删除的元素88
System.out.println(arr.size()); //集合大小 8
arr.forEach1(); //11 22 33 44 55 66 77 99
arr.forEach((Integer integer) -> System.out.print(integer + " ")); //11 22 33 44 55 66 77 99
}
}
第五题:二分查找的应用
public class demo5 {
public static void main(String[] args) {
int[] nums = {};
int target = 0;
int[] rs = isExist(nums,target);
System.out.println(Arrays.toString(rs));
}
//查找目标值对应的最左边的位置
public static int getLeftIndex(int[] nums, int target){
int rs = -1; //数据不存在为-1
//二分查找
int left = 0;
int right = nums.length-1;
while (left<=right){
int middle = (left + right) / 2;
if(nums[middle]==target){
rs = middle; //先临时存放第一次找到目标值的位置
//二分查找该元素的 左边 是否还存在目标值
right = middle - 1;
}else if(nums[middle] < target){
left = middle + 1;
}else if(nums[middle] > target){
right = middle - 1;
}
}
return rs;
}
//查找目标值对应的最右边的位置
public static int getRightIndex(int[] nums, int target){
int rs = -1; //数据不存在为-1
//二分查找
int left = 0;
int right = nums.length-1;
while (left<=right){
int middle = (left + right) / 2;
if(nums[middle]==target){
rs = middle; //先临时存放第一次找到目标值的位置
//二分查找该元素的 右边 是否还存在目标值
left = middle + 1;
}else if(nums[middle] < target){
left = middle + 1;
}else if(nums[middle] > target){
right = middle - 1;
}
}
return rs;
}
//复杂度O(log2n)
public static int[] isExist(int[] nums, int target) {
int[] rs = {-1,-1}; //记录返回值
if(nums == null ||nums.length == 0){ //如果 数组不存在 或 数组为空
return rs;
}
//数组不为空
rs[0] = getLeftIndex(nums,target);
rs[1] = getRightIndex(nums,target);
return rs;
}
//复杂度O(n)
public static int[] isExist1(int[] nums, int target) {
int[] rs = new int[2];
int count = 0; //记录第几次找到该数字
for (int i = 0; i < nums.length; i++) {
if(nums[i] == target && count == 0){ //第一次找到该数字
rs[0] = i;
count++;
}else if(nums[i] == target && count != 0){ //不是第一次找到该数字
rs[1] = i;
count++;
}
}
if(count == 0){ //说明未找到
rs[0] = -1;
rs[1] = -1;
}
return rs;
}
}
第六题:手写链表、反转链表
//MyLinkedList
public class MyLinkedList<E> {
private int size;
/**
* 定义了一个私有的内部类,作为链表的结点
*/
public static class Node<E>{
E data;
Node<E> next;
public Node(E data, Node<E> next) {
this.data = data;
this.next = next;
}
}
public Node<E> add(){
Node<E> head = null;
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请您输入当前结点的数据值(exit为结束):");
String data = sc.next();
if(data.equals("exit")){ //如果输入的是exit则结束
break;
}
//输入不是exit
if(head==null){ //第一次创建结点
head = new Node(data,null);
size++;
}else{
//已存在头结点,往后插入结点(尾插法)
Node<E> temp = head;
//让temp走到尾部
while(temp.next != null){
temp = temp.next;
}
//把当前结点值创建出来,加入尾部
temp.next = new Node(data,null);
size++;
}
}
return head; //返回链表是返回链表的头结点
}
public Node<E> reverse(Node<E> head,int left,int right){
if(head == null || left < 1 || left > size || right < 1 || right > size || left >= right){
return head;
}
//反转
//先找到左结点的位置
//从左结点遍历到右结点,然后把数据存到集合中
Node<E> first = head; //遍历结点标识
Node<E> mark = null; //记录左结点
List<E> data = new ArrayList<>();
int index = 0;
while(first != null){
index++;
if(index == left){
mark = first;
}
if(index>=left && index<=right){
data.add(first.data);
}
if(index == right){
break;
}
first = first.next;
}
//倒序遍历集合
for (int i = data.size()-1; i >= 0; i--) {
E e = data.get(i);
mark.data = e;
mark = mark.next;
}
return head;
}
public void forEach(Node<E> head){
if(head == null){
System.out.println(head);
return;
}
while(head != null){
System.out.print(head.data+" ");
head = head.next;
}
System.out.println();
}
}
//demo6
public class demo6 {
public static void main(String[] args) {
MyLinkedList<String> list = new MyLinkedList<>();
MyLinkedList.Node<String> head = list.add();
list.forEach(head);
MyLinkedList.Node<String> head2 = list.reverse(head,2,5);
list.forEach(head2);
}
}