写在开始 :
① 本文主要记录笔者目前实际遇到过的代码题,主要是二分查找,冒泡排序,DCL单例模式和 一道关于字符串的处理问题, 小计八千多字,300多行, 阅读花费时间不多,;
② 建议每一种至少会手敲一种代码实现方式,其余思路了解即可;(必须盲敲一种解决办法, 先实现再优化!)
③ 仅用作个人记录, 复习交流, 希望有所帮助!
public class BinarySearch_01 {
public static void main(String[] args) {
int[] arr = {1,5,8,11,19,23,45,48,49,50,66};
int target = 48;
int idx = binarySearch(arr,target);
System.out.println(idx);
}
private static int binarySearch(int[] arr, int target) {
int l = 0, r = arr.length -1, m;
while (l <= r){
m = (l+r)/2;
if (arr[m] == target){
return m;
} else if (arr[m] > target){
r = m-1;
} else {
l = m+1;
}
}
return -1;
}
}
:::info
public class IntOverFlow {
public static void main(String[] args) {
int l = 0;
int r = Integer.MAX_VALUE -1 ;
int m = l + (r-l)/2;
System.out.println(m);//1073741823
l= m+1;
m= l + (r-l)/2;
System.out.println(m);//1610612735
System.out.println(r);//2147483646
}
}
public class IntOverFlow {
public static void main(String[] args) {
int l = 0;
int r = Integer.MAX_VALUE -1 ;
int m = l + (r-l) >>> 1;
System.out.println(m);//1073741823
l= m+1;
m= (r+l) >>> 1;
System.out.println(m);//1610612735
System.out.println(r);//2147483646
}
}
tip
以上是以 jdk 中Arrays.binarySearch 实现作为讲解示范,
实际二分查找又很多变体,一旦使用变体实现,那么左右边界的选取会有变化, 力扣上有三种,可以参考.
package ithm;
import java.util.Arrays;
public class BubbleSort {
public static void main(String[] args) {
int[] arr = {5, 7, 9, 4, 1, 3, 2, 8};
bubble(arr);
}
private static void bubble(int[] arr) {
for (int j = 0; j < arr.length -1; j++) {
for (int i = 0; i < arr.length-1; i++) {
if (arr[i] > arr[i + 1]) {
swap(arr, i, i + 1);
}
}
System.out.println("第" + (j + 1) + "轮冒泡" + Arrays.toString(arr));
}
}
private static void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
package ithm;
import java.util.Arrays;
public class BubbleSort {
public static void main(String[] args) {
int[] arr = {5, 7, 9, 4, 1, 3, 2, 8};
bubble(arr);
}
private static void bubble(int[] arr) {
for (int j = 0; j < arr.length -1; j++) {
for (int i = 0; i < arr.length-1-j; i++) { //减少比较次数
if (arr[i] > arr[i + 1]) {
swap(arr, i, i + 1);
}
}
System.out.println("第" + (j + 1) + "轮冒泡" + Arrays.toString(arr));
}
}
private static void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
package ithm;
import java.util.Arrays;
public class BubbleSort {
public static void main(String[] args) {
int[] arr = {5, 7, 9, 4, 1, 3, 2, 8};
bubble(arr);
}
private static void bubble(int[] arr) {
for (int j = 0; j < arr.length -1; j++) {
boolean flag = false; // 是否发生交换
for (int i = 0; i < arr.length-1-j; i++) {
if (arr[i] > arr[i + 1]) {
swap(arr, i, i + 1);
flag = true;
}
}
System.out.println("第" + (j + 1) + "轮冒泡" + Arrays.toString(arr));
if (!flag){
break;
}
}
}
private static void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
private static void bubble(int[] arr) {
for (int j = 0; j < arr.length -1; j++) {
boolean flag = false; // 是否发生交换
for (int i = 0; i < arr.length-1-j; i++) {
if (arr[i] > arr[i + 1]) {
swap(arr, i, i + 1);
flag = true;
}
}
System.out.println("第" + (j + 1) + "轮冒泡" + Arrays.toString(arr));
if (!flag){
break;
}
}
}
升序冒泡排序: 依次比较数组中相邻两个元素大小,如果后一个数相对更小,则交换两个元素,两两都比较一遍称为一轮冒泡,结果最大的元素在最后;
重复该步骤,直到整个数组有序;
:::
// 使用双重检查锁定(Double-Checked Locking,DCL)实现的单例模式
public class Singleton {
// 私有的该类的引用
private volatile static Singleton instance;
private Singleton() {
// 私有构造函数,防止外部实例化
}
// 提供公共的访问方式
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
//volatile 关键字用于确保变量可见性和禁止指令重排序,从而避免 DCL 的潜在问题。在 getInstance()
//方法中,首先检查实例是否已经被创建,如果没有,则获取锁进行同步,并再次检查实例是否已被创建。
//这样可以避免多个线程同时进入同步块创建实例,提高了性能。
public class Demo {
// 构造器私有化
private Demo() {
}
// 属性私有化
private volatile static Demo demo ;
// 公共的访问方式
public static Demo getInstance() {
if (demo == null) {
synchronized (Demo.class) {
if (demo == null) {
demo = new Demo();
}
}
}
return demo;
}
}
关于设计模式,
第一个单例模式的话, 大家最好实现简单的饿汉式,懒汉式以及DCL的实现方式, 并对静态内部类,枚举类等其余方式简单了解,还有通过序列化等方式破坏单例也可以简单了解;
第二个合计23种设计模式, 大家尽量熟悉常用的几款设计模式, 比如单例,工厂,策略,责任链,代理… 剩余的设计模式了解一下, 无论是面试还是后续工作擅于发现的话都高频出现 ! 比如Spring框架涉及到的十几种设计模式…
//输入:CM->123->RM->123->256->234->178->178->RO>256->179 / 输入字符串由”CM、RM、RO”这三个字符串和若干数字通过”->”组合而成,中间不存在空格,”->”表示数字或者字符串之间的递进关系; // 输出:[123,234,178,256,179]
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
// 基于正则表达式和哈希集合
public class Demo {
public static void main(String[] args) {
String input = "CM->123->RM->123->256->234->178->178->RO>256->179";
List<Integer> numbers = parseInputString(input);
System.out.println(numbers);
}
public static List<Integer> parseInputString(String input) {
String[] tokens = input.split("->");
Set<String> visited = new HashSet<>();
List<Integer> numbers = new ArrayList<>();
for (String token : tokens) {
if (token.matches("-?\d+")) { // 判断是否为数字
Integer number = Integer.parseInt(token);
if (!visited.contains(number.toString())) {
numbers.add(number);
visited.add(number.toString());
}
}
}
return numbers;
}
}
package com.itkaka;
/*
* 从字符串中提取不重复的数字?输入:CM->123->RM->123->256->234->178->178->RO->256->179,输出[123,234,178,256,179]。
* */
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Demo3 {
public static void main(String[] args) {
String s = "CM->123->RM->123->256->234->178->178->RO->256->179";
String[] strs = s.split("\\D+");
System.out.println(Arrays.toString(strs)); //[, 123, 123, 256, 234, 178, 178, 256, 179]
List<Integer> list = new ArrayList<>();
// TODO
// 使用set 集合方法去重,
}
}
// 方法一:使用正则表达式和LinkedHashSet
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
String input = "CM->123->RM->123->256->234->178->178->RO>256->179";
Set<Integer> numbers = extractUniqueNumbers(input);
System.out.println(numbers);
}
public static Set<Integer> extractUniqueNumbers(String input) {
Set<Integer> numbers = new LinkedHashSet<>();
Pattern pattern = Pattern.compile("\d+");
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
numbers.add(Integer.parseInt(matcher.group()));
}
return numbers;
}
}
//使用正则表达式 \d+ 匹配连续的数字,并使用 Matcher 对象逐个查找数字。然后,将不重复的数字添加
//到 LinkedHashSet 中,由于 LinkedHashSet 保留插入顺序,结果集将按照数字第一次出现的顺序排列。
// 使用Stream API和去重操作
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Demo1 {
public static void main(String[] args) {
String input = "CM->123->RM->123->256->234->178->178->RO>256->179";
List<Integer> numbers = extractUniqueNumbers(input);
System.out.println(numbers);
}
public static List<Integer> extractUniqueNumbers(String input) {
List<Integer> numbers = Stream.of(input.split("\D+"))
.filter(s -> !s.isEmpty())
.map(Integer::parseInt)
.distinct()
.collect(Collectors.toList());
return numbers;
}
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Demo1 {
public static void main(String[] args) {
/*
\\D+:表示至少一个非数字。
String[] strs = s.split("\\D+");:将字符串中的非数字字符作为分隔符,分割成多个子字符串并保存到一个字符串数组中。
if (!str.isEmpty()) { list.add(Integer.parseInt(str)); }:将子字符串转换为整数并存储到一个数组中。
Integer[] nums = list.toArray(new Integer[0]);:将存储数字的List转换为数组。*/
String s = "CM->123->RM->178-179";
String[] strs = s.split("\\D+");
List<Integer> list = new ArrayList<>();
for (String st:strs
) {
if (!st.isEmpty()){
list.add(Integer.parseInt(st));
}
}
Integer[] nums = list.toArray(new Integer[0]);
System.out.println(nums);// [Ljava.lang.Integer;@57829d67
System.out.println(Arrays.toString(nums));//[123, 178, 179]
}
}
使用 split(“\D+”) 将字符串分割为数字和非数字部分,并且通过 filter 方法过滤掉空字符串。然后,使用map 方法将字符串转换为整数,再通过 distinct 方法去除重复的数字,最后使用 collect 方法收集结果为列表。
/*
* 编写一个函数来查找字符串数组中的最长公共前缀。
输入:strs = ["flower","flow","flight"]
输出:"fl"
* */
public class Demo2 {
public static void main(String[] args) {
String[] strs = {"flower","flow","flight"};
System.out.println(result(strs)); // fl
}
// 返回一个公共前缀的字符串(可能是空)
public static String result(String[] strs) {
// 参数非空校验
if (strs == null || strs.length == 0) {
return "";
}
// 依次遍历元素,看是否重复,不重复直接返回,重复继续往后读
String temp = strs[0];
for (int i = 1; i < strs.length; i++) {
String str1 = strs[i];
int j = 0;
while (j < temp.length() && j < str1.length() && temp.charAt(j) == str1.charAt(j)) {
j++;
}
temp = temp.substring(0, j);
// 这里需要再加一个校验
if (temp.isEmpty()){
break;
}
}
return temp;
}
}
写在最后 :
周六了, 下着小雨 , 希望这篇博文 能够对大家有帮助 !
码字不易, 希望大家能够点赞加关注, 祝愿大家 代码0 BUG, 技术和收入节节高!