一、算法
1.1 字符串操作相关
1 字符串只包括数字和*,重排使所有的*在左,数字在右并保持顺序不变.
public class Demo {
public static void main(String[] args) {
String str = "123";
try {
String res = dealStr2(str);
System.out.println(res);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 方式一: 字符串转char数组, 数字元素后移, 前面填充*
*/
public static String dealStr(String str) throws Exception {
// 以下情况(str是:null,纯数字,纯*号), 则直接返回原字符串
if (null == str || str.matches("\\d+") || str.matches("\\*+")) {
return str;
}
// 如果非数字与*组合, 直接抛出异常
if (!str.matches("[\\d\\*]+")) {
throw new Exception("输入了非法的字符串!");
}
// 字符串转字符数组, 数字元素向后移动
char[] chars = str.toCharArray();
int index = str.length() - 1;
for (int i = str.length() - 1; i >= 0; i--) {
if (chars[i] != '*') {
chars[index--] = chars[i];
}
}
// 填补前面的*号
for (; index >= 0; index--) {
chars[index] = '*';
}
// 字符数组转string后返回
return new String(chars);
}
/**
* 方式二: 正则移除字符串中的数字 + 正则移除字符串中的*号
*/
public static String dealStr2(String str) throws Exception {
// 以下情况(str是:null,纯数字,纯*号), 则直接返回原字符串
if (null == str || str.matches("\\d+") || str.matches("\\*+")) {
return str;
}
// 如果非数字与*组合, 直接抛出异常
if (!str.matches("[\\d\\*]+")) {
throw new Exception("输入了非法的字符串!");
}
// 返回结果
return str.replaceAll("\\d", "") + str.replaceAll("\\*", "");
}
}
1.2 int数组操作
1 一个int数组,使其奇数在左,偶数在右.
1 思路
1)左指针从数组的左侧起找偶数,找到就停止;
2)右指针从数组的右侧起找奇数,找到就停止;
3)交换两个指针上的元素;
4)重复上面的步骤,两个指针碰到一起就结束;
2 代码demo
private static void sort(int[] array) {
// 1 特殊情况的预处理
if (null == array || array.length == 1) {
return;
}
// 定义变量
int left = 0;
int right = array.length - 1;
int temp;
while (left < right) {
// 1 从左边开始查找偶数
while (left < right && array[left] % 2 == 1) {
left++;
}
// 2 从右边开始查找奇数
while (right > left && array[right] % 2 == 0) {
right--;
}
// 3 交换两个指针上的异类元素
if (left < right) {
temp = array[left];
array[left] = array[right];
array[right] = temp;
}
}
}
2 两个很大的整数相加
1 思想: 模拟加法运算
1)以字符串的形式传入两个整数
2)字符串的元素存入两个int数组
3)数组中对应的元素相加(分割的思想)
2 代码demo
private static String add(String s1, String s2) {
// 1 统一化,s1存较大的是,s2存较小的数
if (s1.length() < s2.length()) {
String temp;
temp = s1;
s1 = s2;
s2 = temp;
}
// 2 构造3个int[]容器
int len = s1.length();
int[] x1 = new int[len]; //存放参数1
int[] x2 = new int[len]; //存放参数2
int[] sum = new int[len + 1]; //存放两个参数的和以及进位
// 3 参数1的各位数字存入容器
for (int i = 0; i < len; i++) {
x1[i] = s1.charAt(i) - '0';
}
// 4 参数2的各位数字存入容器
int t = len - s2.length();
for (int i = t; i < len; i++) {
x2[i] = s2.charAt(i - t) - '0';
}
// 5 逐位求两个参数的和,并存入和容器中
for (int i = len - 1; i >= 0; i--) {
sum[i + 1] += x1[i] + x2[i]; //求本位上的总和
sum[i] = sum[i + 1] / 10; //向高位的进位
sum[i + 1] %= 10; // 本位的剩余
}
// 6 转结果
StringBuilder result = new StringBuilder();
for (int aSum : sum) {
result.append(aSum);
}
// 7 去前面0的操作
String result2 = result.toString();
int count = 0;
int len2 = result2.length();
while (count < len2 && result.charAt(count) == '0') {
count++;
}
return result2.substring(count);
}
3 判断两个int数组是否有相同的元素.
1 思路
1)两个数组中的元素放入分别(除去自身数组中有相同元素的影响)放入Set集合中,求出这两个set集合的元素个数之和size1;
2)把一个set中的所有元素放入另一个set中,求出此集合的元素个数size2;
3)如果size2<size1,则说明两个数组中有相同的元素,否则两个数组中没有相同的元素.
2 代码demo
private static boolean isSame(int[] array, int[] array2) {
// 1 定义两个去重的容器
Set<Integer> set = new HashSet<Integer>();
Set<Integer> set2 = new HashSet<Integer>();
// 2 两个数组的元素分别放入两个Set集合(去除自己中的重复元素)
for (int i : array) {
set.add(i);
}
for (int i : array2) {
set2.add(i);
}
// 3 长度比较法
int len = set.size() + set2.size();
set.addAll(set2);
return len > set.size();
}
4 求一个int数组的子数组元素之和的最大值.
1 思路
定住左边界之后, 依次移动右边界,依次遍历所有子数组的和值, 从而找出最大值.
2 代码demo
private static int getSum(int[] array) {
int max = array[0];
int sum;
for (int i = 0; i < array.length; i++) {
sum = 0;
for (int j = i; j < array.length; j++) {
sum += array[j];
if (max < sum) {
max = sum;
}
}
}
return max;
}
1.3 二分查找
1 数组必须是升序排列的
2 代码demo
/**
* 找到返回对应位置的索引, 其他情况返回-1
*/
private static int binarySort(int[] array, int value) {
// 1 特殊情况处理
if (null == array) {
return -1;
}
// 定义变量,进行二分查找
int left = 0;
int right = array.length - 1;
int middle;
while (left <= right) {
// 中间位置的索引
middle = (left + right) / 2;
// 找到处理
if (value == array[middle]) {
return middle;
}
// value值小时, 修改右指针
if (value < array[middle]) {
right = middle - 1;
}
// value值大时, 修改左指针
if (value > array[middle]) {
left = middle + 1;
}
}
// 找不到时返回-1
return -1;
}
1.4 排序
1 插入排序
1 思想:从第二个元素起,依次插入到前面已经排好序的数组中(挖坑填坑法).
2 代码demo
private static void insertSort(int[] array) {
// 1 特殊情况处理
if (null == array || array.length == 1) {
return;
}
// 2 逐位放到正确的位置上
int tmp;
int j;
for (int i = 1; i < array.length; i++) {
tmp = array[i];
for (j = i - 1; j >= 0; j--) {
if (array[j] <= tmp) {
break;
}
array[j + 1] = array[j];
}
array[j + 1] = tmp; // 把你存放到正确位置
}
}
2 希尔排序
1 思路
希尔排序也成为“缩小增量排序”,其基本原理是,现将待排序的数组元素分成多个子序列,使得每个子序列的元素个数相对较少,
然后对各个子序列分别进行直接插入排序,待整个待排序列“基本有序”后,最后在对所有元素进行一次直接插入排序。因此,我们
要采用跳跃分割的策略:将相距某个“增量”的记录组成一个子序列,这样才能保证在子序列内分别进行直接插入排序后得到的结果
是基本有序而不是局部有序。希尔排序是对直接插入排序算法的优化和升级。
2 代码demo
private static void shellSort(int[] array) {
// 1 特殊情况的预处理
if (null == array || array.length == 1) {
return;
}
// 2 逐位放到正确的位置上
int tmp;
int j;
for (int count = array.length / 2; count > 0; count /= 2) { // 缩小增量
for (int i = count; i < array.length; i++) { // 此增量的子数组进行插入排序
tmp = array[i];
for (j = i - count; j >= 0; j -= count) { // 元素逐步插入到正确的位置
if (array[j] <= tmp) { // 找到正确的位置就停止
break;
}
array[j + count] = array[j]; // 不是正确的位置时,元素向后移动
}
// 3 把你存放到正确位置
array[j + count] = tmp;
}
}
}
3 快速排序
1 思路
(每次排好一个元素的位置) 以某个元素为基准值,不大于基准值的元素放在它左面,
大于基准值的元素放在它右面.这样基准值的位置就正确了.然后基准值的左右两边
重复上面的操作.
2 代码demo
public static void sort(int[] arr, int left, int right) {
//递归停止条件
if (left>=right) {
return;
}
// 初始化
int base = arr[left]; // 挖出第一个坑(以最左边的元素为基准)
int i = left;
int j = right;
// 循环填坑
while (i < j) {
// 从右边找一个比基准小的填充左边的坑
while (i < j && arr[j] > base) {
j--;
}
arr[i] = arr[j];
// 从左边找一个比基准大的填充右边的坑
while (i < j && arr[i] <= base) {
i++;
}
arr[j] = arr[i];
}
// 填充最后一个坑
arr[i]=base;
// 递归调用
sort(arr, left, i-1);
sort(arr, i+1, right);
}
4 归并排序
private static void mergeSort(int[] array) {
if (null == array || array.length == 1) {
return;
}
mergeSort2(array, 0, array.length - 1);
}
private static void mergeSort2(int[] array, int z, int y) {
if (z >= y) {
return;
}
int m = (z + y) / 2;
mergeSort2(array, z, m);
mergeSort2(array, m + 1, y);
merge(array, z, m, y);
}
// 利用两个临时的桶暂存两个分区的数据,两个桶中的数据有序的放回原数组.
private static void merge(int[] array, int z, int m, int y) {
// 定义两个临时桶
int[] a = new int[m - z + 1];
int[] a2 = new int[y - m];
// 原数组元素复制到临时桶
System.arraycopy(array, z, a, 0, a.length);
System.arraycopy(array, m + 1, a2, 0, a2.length);
// 有序从临时桶取数放入到原数组
int x = 0;
int x2 = 0;
while (x < a.length && x2 < a2.length) {
if (a[x] < a2[x2]) {
array[z++] = a[x++];
} else {
array[z++] = a2[x2++];
}
}
// 桶1的剩余数据放入原数组
while (x < a.length) {
array[z++] = a[x++];
}
// 桶2的剩余数据放入原数组
while (x2 < a2.length) {
array[z++] = a2[x2++];
}
}
5 选择排序
1 思路
找到最小元素的索引位置,和第一个索引上的元素互换; 找到次最小元素的索引位置,
和第二个索引上的元素互换;重复上述操作到结束.
2 代码demo
private static void selectSort(int[] array) {
// 特殊情况处理
if (null == array || array.length == 1) {
return;
}
// 逐渐寻找最小元素放到合适位置
int index;
for (int i = 0; i < array.length-1; i++) {
index = i;
for (int j = i + 1; j < array.length; j++) {
if (array[index] > array[j]) {
index = j;
}
}
if (index != i) {
int temp = array[i];
array[i] = array[index];
array[index] = temp;
}
}
}
6 冒泡排序
1 思路
相邻元素两两比较, 大的向后移动, 直到length-1冒泡或全局有序标记位flag成立.
2 代码demo
private static void maoPaoSortort(int[] array) {
// 特殊情况处理
if (null == array || array.length == 1) {
return;
}
int temp;
boolean flag = true; // 判断是否能提前结束的标记位
for (int i = 0; i < array.length - 1; i++) {
// 第i+1次冒泡
for (int j = 0; j < array.length - 1 - i; j++) {
if (array[j] >= array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
flag=false;
}
}
// 判断是否能提前结束排序
if(flag){
break;
}else {
flag=true;
}
}
}