java快排代码边界,java实现快速排序&最长子字符串

快速排序

简述

快速排序是一种排序执行效率很高的排序算法,它利用分治法来对待排序序列进行分治排序,它的思想主要是通过一趟排序将待排记录分隔成独立的两部分,其中的一部分比关键字小,后面一部分比关键字大,然后再对这前后的两部分分别采用这种方式进行排序,通过递归的运算最终达到整个序列有序,下面我们简单进行阐述。

先用例子理解快排的实现思路

比如对 4,1,8,5,3,2,9,10,6,7 这10个数字进行排序,

1.对第一个数字4排序,这里先想一下,当我们把4排好序后它左边的数字应该都比它小,而且它右边的数字应该都比它大,做到这样后4这个数字的位置就排好了。那怎么达到这样的效果呢?

第一步:我们先从数组的右边开始循环,跟4比较大小,如果比4小,那就和4交换位置,循环过程如下:

7>4,不交换

6>4,不交换

10>4,不交换

9>4,不交换

2<4,交换,4和2交换后数组变 2,1,8,5,3,4,9,10,6,7,此次循环到了数组下标为5的位置

第二步:从数组的左边开始循环,跟4比较大小,如果比4大,那就和4交换位置,循环过程如下:

2<4,不交换

1<4,不交换

8>4,交换,8和4交换后数组变为 2,1,4,5,3,8,9,10,6,7,此次循环到了数组下标为2的位置

第三步:这里注意,要左右两边同时循环和4比较大小,直到两边循环相遇。第一步从右向左循环到了下标为5(当前对应数字8)的位置,继续循环过程如下:

3<4,交换,3和4交换后数组变为 2,1,3,5,4,8,9,10,6,7,此次循环到了数组下标为4的位置

第四步:第二步从左向右循环到了下标为2(当前对应数字3)的位置,继续循环过程如下:

5>4,交换,5和4交换后数组变为2,1,3,4,5,8,9,10,6,7,此次循环到了数组下标为3的位置,上一步从右向左也循环到了下标为4的位置,已经相遇了。到此4也已经放到正确的位置了,次轮循环结束。

但是4左边的2,1,3和右边的5,8,9,10,6,7还是乱序的,所以继续对两边的数字重复上面的步骤。

2.对数组的前3个元素2,1,3排序,首先对第一个数字2排序,过程如下:

第一步:从右向左循环和2比较大小

3>2,不交换

1<2,交换,1和2交换后变为1,2,3,此次循环到了数组下标为1的位置,排序已经完成。

3.对数组的后6个元素5,8,9,10,6,7排序,首先对第一个数字5排序,5已经在正确位置上,再继续对后面的5个元素重复上面的步骤循环排序。

用Java实现快排

public class QuickSort {

public static void main(String[] args) {

int[] arr = new int[]{4, 1, 8, 5, 3, 2, 9, 10, 6, 7};

quickSort(arr, 0, 9);

// 打印

for (int i = 0; i < arr.length; i++) {

System.out.print(arr[i] + ",");

}

}

/**

* 递归循环实现快排

*

* @param arr 数组

* @param startIndex 快排的开始下标

* @param endIndex 快排的结束下标

*/

public static void quickSort(int[] arr, int startIndex, int endIndex) {

if (arr == null || arr.length == 0) {

return;

}

int start = startIndex, end = endIndex;

//target是本次循环要排序的元素,每次循环都是确定一个元素的排序位置,这个元素都是开始下标对应的元素

int target = arr[startIndex];

//开始循环,从两头往中间循环,相遇后循环结束

while (start < end) {

//从右向左循环比较,如果比target小,就和target交换位置,让所有比target小的元素到target的左边去

while (start < end) {

if (arr[end] < target) {

swap(arr, start, end);

break;

}

end--;

}

//从左向右循环比较,如果比target大,就和target交换位置,让所有比target大的元素到target的右边去

while (start < end) {

if (arr[start] > target) {

swap(arr, start, end);

break;

}

start++;

}

}

//确定target的排序后,如果target左边还有元素,继续递归排序

if ((start - 1) > startIndex) {

quickSort(arr, startIndex, start - 1);

}

//确定target的排序后,如果target右边还有元素,继续递归排序

if ((end + 1) < endIndex) {

quickSort(arr, end + 1, endIndex);

}

}

/**

* 根据下标交换数组的两个元素

*

* @param arr 数组

* @param index1 下标1

* @param index2 下标2

*/

public static void swap(int[] arr, int index1, int index2) {

int temp = arr[index1];

arr[index1] = arr[index2];

arr[index2] = temp;

}

}

运行结果:

1,2,3,4,5,6,7,8,9,10,

无重复字符的最长子串

参考:https://www.cnblogs.com/ariel-dreamland/p/8668286.html

题目描述:

给定一个字符串,找出不含有重复字符的 最长子串 的长度。

示例:

给定 "abcabcbb" ,没有重复字符的最长子串是 "abc" ,那么长度就是3。

给定 "bbbbb" ,最长的子串就是 "b" ,长度是1。

给定 "pwwkew" ,最长子串是 "wke" ,长度是3。请注意答案必须是一个子串,"pwke" 是 子序列 而不是子串。

方法一:暴力法

直觉

逐个检查所有的字符串,看它是否不含有重复的字符。

算法

假设我们有一个函数boolean allUnique(String substring) ,如果子字符串中的字符都是唯一的,它会返回true,否则会返回false。 我们可以遍历给定字符串s的所有可能的子字符串并调用函数allUnique。 如果事实证明返回值为true,那么我们将会更新无重复字符子串的最大长度的答案。

现在让我们填补缺少的部分:

为了枚举给定字符串的所有子字符串,我们需要枚举它们开始和结束的索引。假设开始和结束的索引分别为 i 和 j。那么我们有 0≤i

要检查一个字符串是否有重复字符,我们可以使用集合。我们遍历字符串中的所有字符,并将它们逐个放入set中。在放置一个字符之前,我们检查该集合是否已经包含它。如果包含,我们会返回false。循环结束后,我们返回true。

public class Solution {

public int lengthOfLongestSubstring(String s) {

int n = s.length();

int ans = 0;

for (int i = 0; i < n; i++)

for (int j = i + 1; j <= n; j++)

if (allUnique(s, i, j)) ans = Math.max(ans, j - i);

return ans;

}

public boolean allUnique(String s, int start, int end) {

Set set = new HashSet<>();

for (int i = start; i < end; i++) {

Character ch = s.charAt(i);

if (set.contains(ch)) return false;

set.add(ch);

}

return true;

}

}

方法二:滑动窗口

滑动窗口是数组/字符串问题中常用的抽象概念。 窗口通常是在数组/字符串中由开始和结束索引定义的一系列元素的集合,即 [i, j)(左闭,右开)。而滑动窗口是可以将两个边界向某一方向“滑动”的窗口。例如,我们将 [i, j)向右滑动 1 个元素,则它将变为 [i+1,j+1)(左闭,右开)。

回到我们的问题,我们使用 HashSet 将字符存储在当前窗口 [i,j)(最初 j=i)中。 然后我们向右侧滑动索引 j,如果它不在 HashSet 中,我们会继续滑动 jj。直到 s[j] 已经存在于 HashSet 中。此时,我们找到的没有重复字符的最长子字符串将会以索引 i 开头。如果我们对所有的 i 这样做,就可以得到答案。

public int lengthOfLongestSubstring(String s) {

int n = s.length();

Set set = new HashSet<>();

int ans = 0, i = 0, j = 0;

while (i < n && j < n) {

// try to extend the range [i, j]

if (!set.contains(s.charAt(j))){

set.add(s.charAt(j++));

ans = Math.max(ans, j - i);

}

else {

set.remove(s.charAt(i++));

}

}

return ans;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值