快排开场(快速排序)
原理:
1. 定义一个标杆,初始标杆为数组第0个位置,把标杆取出来放到外面。标杆作用:比标杆小的数字放到标杆左边,比标杆大的数字放到标杆右边。
2. 涉及两个循环,一个从左往右的循环,称为i循环;一个从右往左的循环,称为j循环。
3. j先开始往左走,发现比标识小的数,抛给i,这时j就站住不动,然后i开始往右走,发现比标识大的数,抛给j,这时i就站住不动,让j走,就这样像抛绣球一样抛来抛去,小数抛到左边,大数抛到右边,当i和j越走越近,走到最后i和j重复的时候就是标识所在的地方。此时的结果并不是排好序的,只是把数组分成了两部分,左边的数比5小,右边的数比5大。
4. 把标识的左右两边又看成是完整的两个数组,不断的劈开劈开,当劈开越小,到3个数的时候,小的在左边,大的在右边,肯定是有序的。多个3个数的时候,组合到一起就是完整的有序的数组。

代码:
public static void main(String[] args) {
//play(new File("D:\\yy"));
int[] ints = {5,4,6,2,7,3,9,8};
quickSort(ints,0,ints.length-1);
for (int anInt : ints) {
System.out.print(anInt +" ");
}
}
/**
* 快速排序 第二步 递归方法,不断调用第一步找中间位置
* @param ints 数组
* @param i 开始位置
* @param j 结束位置
* @return
*/
public static void quickSort(int[] ints,int i,int j) {
if(i < j){
int index = sortUnit(ints, i, j); // 找到中间位置
quickSort(ints,i,index-1); // 左边 把5左边当成一个小的数组继续找
quickSort(ints,index+1,j); // 右边 把5右边当成一个小的数组继续找
}
}
/**
* 快速排序 第一步 小数在标杆左边,大数在标杆右边,此时未排序
* @param ints 数组
* @param i 开始位置
* @param j 结束位置
* @return
*/
static int sortUnit(int[] ints,int i,int j){
int num = ints[i]; // 标杆 第一次时为数组[0]
while (i < j){ // j和i开始不断找,直到中间位置
while (i < j){
if(ints[j] < num){ // j负责找小的,扔给i
ints[i] = ints[j];
break; // 找到就不能动了,让i开始找大的
}
j--; // 没找到就继续往前走
}
while (i < j){
if(ints[i] >= num) { // i负责找大的,扔给j
ints[j] = ints[i];
break; // 找到就不能动了,让j开始找小的
}
i++; // 没找到就继续往前走
}
}
// 循环结束后,说明标杆在i和j碰面的地方
ints[i] = num;
return i;
}
/**
* 获取当前文件夹下所有子文件夹/文件 递归调用
* @param file
*/
static void play(File file){
File[] files = file.listFiles();
for (File f : files) {
if(f.isFile()){
System.out.println(f.getName());
}else {
play(f);
}
}
}
字符串相关
/**
* 1. 找出字符串中出现次数最多的字符
*/
@Test
public void test(){
String str = "sfasjlfaskfjlsajflakjaafadslfjsdlk";
char res = str.charAt(0);
int max = 0;
Map<Character,Integer> map = new HashMap<>();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
Integer count = map.get(c);
if(count == null){ // 字符没有出现过
count = 1;
}else {
count++;
}
map.put(c,count);
if(count > max){
res = c;
max = count;
}
}
System.out.println(res+" 出现次数最多,出现:"+max+" 次");
}
/**
* 2. 找出字符串中第一次重复出现的字符
*/
@Test
public void test2(){
String str = "abccba";
Set<Character> set = new HashSet<>();
for (int i = 0; i < str.length(); i++) {
// 添加失败说明已经存在
if(!set.add(str.charAt(i))){
System.out.println("第一次重复出现的字符是:"+str.charAt(i));
break;
}
}
}
/**
* 3. 在字符串中找出第一个只出现一次的字符
*/
@Test
public void test3_1(){
String str = "abcabddsc";
Map<Character, Integer> map = new HashMap<>();
for (int i = 0; i < str.length(); i++) {
Integer count = map.get(str.charAt(i));
if(count == null){
count = 1;
}else{
count++;
}
map.put(str.charAt(i),count);
}
for (int i = 0; i < str.length(); i++) {
if(map.get(str.charAt(i))==1){
System.out.println("第一个只出现一次的字符是:"+str.charAt(i));
break;
}
}
}
/**
* 3. 在字符串中找出第一个只出现一次的字符
*/
@Test
public void test3_2(){
String str = "abcabddsc";
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if(str.indexOf(c) == str.lastIndexOf(c)){
System.out.println("第一个只出现一次的字符是:"+str.charAt(i));
break;
}
}
}
/**
* 4. 统计手机号各个数字个数,按照升序输出
*/
@Test
public void test4(){
int[] count = new int[10];
String mobile = "13894937387";
for (int i = 0; i < mobile.length(); i++) {
char c = mobile.charAt(i);
count[c-'0']++;// 统计每个字符出现的次数,char-'0'是一个整数 a[0] = 5; a[0]++; a[0] = 6;
}
for (int i = 0; i < mobile.length(); i++) {
if(count[i]>0){
System.out.println(i+"出现了"+count[i]+" 次");
}
}
}
/**
* 5. 输入一个字符串,输出为按字节截取字符串,要保证汉字不能被截半个
* 注意:汉字占两个字节 GBK、汉字占三个字节 UTF-8
*/
@Test
public void test5(){
// int len = String.valueOf("人").getBytes().length; // 获取字符的字节数
// System.out.println(len); // 人 的字节数:3
String str = "人ABC们DEF";
int count = 4; // 截取4个字节
int sum = 0; // 已经截取了多少
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
int len = String.valueOf(str.charAt(i)).getBytes().length;
if(sum + len <= count){
sum += len;
sb.append(str.charAt(i));
}else {
break;
}
}
System.out.println("截取"+count+"个字节后字符串为:"+sb.toString());
}
/**
* 6. 写出如下代码中截取efg的代码
* <p id="test">abcdefg</p>
*/
@Test
public void test6(){
String str = "<p id=\"test\">abcdefg</p>";
/*** 使用substring截取 ***/
String reg = "efg"; // 要匹配的字符串
int index = str.indexOf(reg); // 在整个字符串中出现索引的位置
String target = str.substring(index, index + reg.length()); // 从索引位置开始截取,截取字符串的长度
System.out.println("截取的字符串为:"+target);
/*** 使用正则截取 ***/
reg = ".*(efg).*";
Pattern pattern = Pattern.compile(reg);
Matcher matcher = pattern.matcher(str);
if(matcher.find()){
System.out.println("截取的字符串为:"+matcher.group(1));
}
}
/**
* 7. 设计一种反转字符串的算法,例如字符串为src="abddefg",反转后字符串src="gfeddba"
*/
@Test
public void test7(){
String src = "abddefg";
/*** 使用StringBuilder.reverse()反转字符串,非算法 ***/
StringBuilder builder = new StringBuilder(src);
System.out.println("字符串"+src+"反转后为:"+builder.reverse()); // 使用StringBuilder反转
/*** 使用数组反转字符串,首尾互换,换到中间位置 ***/
char[] chars = src.toCharArray();
for(int i=0;i<chars.length/2;i++){
char temp = chars[i];
chars[i] = chars[chars.length-i-1]; // 第i个元素换成末尾和它对应位置的那个元素
chars[chars.length-i-1] = temp;
}
System.out.println("字符串"+src+"反转后为:"+new String(chars));
/*** 使用倒排序遍历反转字符串 ***/
StringBuilder sb = new StringBuilder();
for (int i = src.length()-1; i >= 0; i--) {
sb.append(src.charAt(i));
}
System.out.println("字符串"+src+"反转后为:"+sb.toString());
}
/**
* 8. 将句子按照一定的分割符分割后反转返回
* 举例: 输入"I love the game" 输出"game the love I"
*/
@Test
public void test8(){
String src = "I love the game";
String sep = " ";
String[] arrs = src.split(sep);
StringBuilder builder = new StringBuilder();
for(int i= arrs.length-1;i>=0;i--){
builder.append(arrs[i]);
builder.append(sep); // 将空格加进去
}
// 最后多余的分隔符要去掉
String target = builder.substring(0, builder.length() - sep.length());
System.out.println("句子"+src+"反转后为:"+target);
}
/**
* 9. 给定一个句子,反转句子中每个单词的顺序,同时保留单词和空格的初始位置
* 输入: "Let's take LeetCode contest"
* 输出: "s'teL ekat edoCteeL tsetnoc"
*/
@Test
public void test9(){
String src = "Let's take LeetCode contest";
String[] arrs = src.split(" ");
StringBuilder builder = new StringBuilder();
for (String arr : arrs) {
// 逆向遍历每一个单词
for(int i= arr.length()-1;i>=0;i--){
builder.append(arr.charAt(i));
}
builder.append(" ");
}
// 去掉最末尾的空格
String target = builder.substring(0, builder.length() - 1);
System.out.println("句子"+src+"单词反转后为:"+target);
}
/**
* 10. 判断字符串是不是合法的ipv4地址
* xxx.xxx.xxx.xxx 0~255
*/
@Test
public void test10(){
System.out.println(checkIp("127.0.0.1"));
}
public boolean checkIp(String ip){
String[] arrs = ip.split("\\.");
if(arrs.length !=4){
return false;
}
for (String arr : arrs) {
// 对每个xxx进行转换为数字,转换失败表示不是数字
try {
Integer num = Integer.parseInt(arr);
if(num>255 || num<0){
return false;
}
// 两位不能以0开头
if(!arr.equals("0") && arr.startsWith("0")){
return false;
}
} catch (NumberFormatException e) {
return false;
}
}
return true;
}
大数相加、相乘
/**
* 实现大数的加法
* 例如:
* String a="123456777..."; a.size 大于1000位
* String b="345678999..."; b.size 大于1000位
* 注意: 不是把字符串转数字类型再相加,1000位转换会直接内存溢出
*/
@Test
public void testLargeNumberSum(){
String a = "10001";
String b = "999999";
System.out.println(10001+999999);
char[] large = null; // 大 (位数)
char[] small = null; // 小 (位数)
if(a.length() >= b.length()){
large = a.toCharArray();
small = b.toCharArray();
}else{
large = b.toCharArray();
small = a.toCharArray();
}
// 最终结果的位数为大的数长度加1 最高位可能是0
int[] sums = new int[large.length+1];
// 将大的数放进数组
for (int i = 0; i < large.length; i++) {
// char转数字 char -'0'
sums[i] = large[large.length-i-1] -'0'; // 从个位开始放进去
}
// 将小的数加到数组
for (int i = 0; i < small.length; i++) {
sums[i] += small[small.length-i-1] -'0';
}
for (int i = 0; i < sums.length -1; i++) {
// 从个位开始判断是否进位
if(sums[i] >9){
// 进位给上一位
sums[i+1] += sums[i]/10;
// 当前数就是对10取余
sums[i] %= 10;
}
}
StringBuilder builder = new StringBuilder();
for (int i = sums.length -1; i > 0; i--) {
builder.append(sums[i]);
}
// 判断最高位有没有进位
String result = builder.toString();
if(result.startsWith("0")){
// 截掉最高位
result = result.substring(1);
}
System.out.println(a+"+"+b+"结果为:"+result);
}
/**
* 实现大数的乘法
* 例如:
* String a="123456777..."; a.size 大于1000位
* String b="345678999..."; b.size 大于1000位
*/
@Test
public void testLargeNumberMultiply(){
String a = "689";
String b = "33";
System.out.println(689*33);
char[] large = null; // 大 (位数)
char[] small = null; // 小 (位数)
if(a.length() >= b.length()){
large = a.toCharArray();
small = b.toCharArray();
}else{
large = b.toCharArray();
small = a.toCharArray();
}
// 结果集最高位数为两数位数和
int[] multi = new int[a.length() + b.length()];
for (int j = small.length-1; j >= 0; j--) { // 个位对齐
for (int i = large.length-1; i >= 0; i--) {
int num1 = small[j] - '0';
int num2 = large[i] - '0';
multi[large.length-1-i + small.length-1-j] += num1*num2;
}
}
// 统一处理进位
for (int i = 0; i < multi.length-1; i++) {
// 从个位开始判断是否进位
if(multi[i] >9){
// 进位给上一位
multi[i+1] += multi[i]/10;
// 当前数就是对10取余
multi[i] %= 10;
}
}
StringBuilder builder = new StringBuilder();
for (int i = multi.length-1; i >= 0; i--) {
builder.append(multi[i]);
}
String result = builder.toString();
if(result.startsWith("0")){
// 截掉最高位
result = result.substring(1);
}
System.out.println(a+"*"+b+"结果为:"+result);
}
相乘数组结构:

数组相关
/**
* 1. 求和 最大的子序列
* 给定一个整数序列,A1,A2,...An(可能是负数),求A1~An的一个子序列Ai~Aj,使得Ai到Aj的和最大,并输出子序列的内容
* 暴利破解法: 三层循环,在数据量比较大的情况下,性能不友好
*/
@Test
public void test1_1(){
int[] nums = {-1,-2,1,6,4,1,-10,3};
int step = 1; // 参与求和的元素个数
int maxSum = nums[0];
int start = 0;
int end = 0;
while (step <= nums.length){
// 从第0个开始计算
for (int i = 0; i <= nums.length - step; i++) {
int tempSum = nums[i];
for (int j = i+1; j < i+step; j++) {
tempSum += nums[j];
}
if(tempSum >= maxSum){
start = i;
end = i + step - 1;
maxSum = tempSum;
}
}
step++;
}
StringBuilder builder = new StringBuilder();
for (int i = start; i <= end; i++) {
builder.append(nums[i]).append(",");
}
// 最大的和:12 子序列:1,6,4,1
System.out.println("最大的和:"+maxSum+" 子序列:"+ builder.deleteCharAt(builder.length()-1).toString());
}
/**
* 1. 求和 最大的子序列
* 给定一个整数序列,A1,A2,...An(可能是负数),求A1~An的一个子序列Ai~Aj,使得Ai到Aj的和最大,并输出子序列的内容
* 一层循环,性能友好
*/
@Test
public void test1_2() {
int[] nums = {-1, -2, 1, 6, 4, 1, -10, 3};
int max = nums[0];
// 以第i个元素结尾的最大的子序列的和
int[] sums = new int[nums.length];
sums[0] = nums[0];
int end = 0;
// 以第i个元素结尾的最大的子序列的和 从几开始的
int[] starts = new int[nums.length];
for(int i=1;i<nums.length;i++){
// 它前面的子序列和大于0
if(sums[i-1]>0){
sums[i] = sums[i-1] + nums[i];
starts[i] = starts[i-1];
}else{
sums[i] = nums[i];
starts[i] = i;
}
if(sums[i] >max){
max = sums[i];
end = i;
}
}
StringBuilder builder = new StringBuilder();
for (int i = starts[end]; i <= end; i++) {
builder.append(nums[i]).append(",");
}
// 最大的和:12 子序列:1,6,4,1
System.out.println("最大的和:"+max+" 子序列:"+ builder.deleteCharAt(builder.length()-1).toString());
}
/**
* 2. 数组去重排序
*/
@Test
public void test2_1(){
int[] nums = {1,3,4,6,4,8,5,3,2,4,0,7,4,4};
for (int i = 0; i < nums.length; i++) {
for (int j = i+1; j < nums.length; j++) {
if(nums[i] > nums[j]){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
System.out.println("排序:"+Arrays.toString(nums));
StringBuilder builder = new StringBuilder();
// 去重
for (int i = 0; i < nums.length - 1; i++) {
// 当前数不等于下一个数
if(nums[i] != nums[i+1]){
builder.append(nums[i]).append(",");
}
}
builder.append(nums[nums.length -1]);
System.out.println("去重:"+builder.toString());
}
/**
* 2. 数组去重排序 使用TreeSet
*/
@Test
public void test2_2() {
int[] nums = {1, 3, 4, 6, 4, 8, 5, 3, 2, 4, 0, 7, 4, 4};
Set<Integer> set = new TreeSet<>();
for (Integer num : nums) {
set.add(num);
}
System.out.println("去重并排序:"+ Arrays.toString(set.toArray()));
}
/**
* 3. 有一个正整数数组,存在重复元素,并降序排列,要求满足以下条件并输出:
* a. 按升序输出数组元素
* b. 重复元素仅打印一次
* c. 时间复杂度o(n) o(n):用一个for循环,不要用for循环嵌套
* 示例: 原始数据[2,3,3,6,6,9,10,10,16,18,18] 输出: 2,3,6,9,10,16,18
*/
@Test
public void test3(){
int[] nums = {2,3,3,6,6,9,10,10,16,18,18};
StringBuilder builder = new StringBuilder();
for (int i = 0; i < nums.length - 1; i++) {
// 当前数不等于下一个数
if(nums[i] != nums[i+1]){
builder.append(nums[i]).append(",");
}
}
builder.append(nums[nums.length -1]);
System.out.println("去重:"+builder.toString());
}
/**
* 4. 奇偶调换
* 调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有的偶数位于数组的后半部分,
* 并保证奇数和奇数,偶数和偶数之间的相对位置不变
*/
@Test
public void test4_1(){
int[] nums = {7,6,4,8,9,0,2,1,3,5,4,3};
List<Integer> oddList = new ArrayList<>(); // 奇数
List<Integer> evenList = new ArrayList<>(); // 偶数
for (int num : nums) {
if(num %2 ==0){
evenList.add(num);
}else {
oddList.add(num);
}
}
oddList.addAll(evenList);
System.out.println(oddList.toString()); // [7, 9, 1, 3, 5, 3, 6, 4, 8, 0, 2, 4]
}
/**
* 4. 奇偶调换
* 调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有的偶数位于数组的后半部分,
* 并保证奇数和奇数,偶数和偶数之间的相对位置不变
*/
@Test
public void test4_2(){
int[] nums = {7,6,4,8,9,0,2,1,3,5,4,3};
// 不使用List, 找奇数往前挪,挪到第一个偶数前面就可以了
for (int i = 0; i < nums.length; i++) {
if(nums[i] %2 ==0){ // 偶数
for (int j = i+1; j < nums.length; j++) {
if(nums[j] %2 ==1){ // 奇数
int temp = nums[j];
for(;j>i;j--){
nums[j] = nums[j-1]; // 第一次找到奇数9,6、4、8依次往后挪
}
nums[i] = temp;
break;
}
}
}
}
System.out.println(Arrays.toString(nums)); // [7, 9, 1, 3, 5, 3, 6, 4, 8, 0, 2, 4]
}
/**
* 5. 给出随机的100个数,可能含重复,序号为1-100,按从小到大顺序输出,并输出相应序号
*/
@Test
public void test5_1(){
int[] nums = {7,6,4,8,9,0,2,1,3,5,4,3}; // 随机数
int[] orders = new int[nums.length]; // 序号
for (int i = 0; i < nums.length; i++) {
orders[i] = i+1;
}
// 随机数排序
for (int i = 0; i < nums.length; i++) {
for (int j = i+1; j < nums.length; j++) {
if(nums[i] > nums[j]){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
// 交换序号
temp = orders[i];
orders[i] = orders[j];
orders[j] = temp;
}
}
}
for (int i = 0; i < nums.length; i++) {
System.out.println(nums[i]+" 序号:"+orders[i]);
}
}
2962

被折叠的 条评论
为什么被折叠?



