1.数组排序
class Solution {
public int[] sortArray(int[] nums) {
//冒泡排序
// for(int i = 0;i < nums.length-1;i++){
// for(int j = 0;j < nums.length-1-i;j++){
// if(nums[j] > nums[j+1]){
// int temp = nums[j];
// nums[j] = nums[j+1];
// nums[j+1] = temp;
// }
// }
// }
//插入排序
// for(int i = 1;i<nums.length;i++){
// int insertVal = nums[i];
// int insertIndex = i-1;
// while(insertIndex >=0 &&insertVal < nums[insertIndex]){
// nums[insertIndex+1] = nums[insertIndex];
// insertIndex--;
// }
// nums[insertIndex+1] = insertVal;
// }
//选择排序
// for(int i = 0;i < nums.length-1;i++){
// int minIndex = i;
// int min = nums[i];
// for(int j = i+1;j < nums.length;j++){
// if(min > nums[j]){
// min = nums[j];
// minIndex = j;
// }
// }
// if(minIndex != i){
// nums[minIndex] = nums[i];
// nums[i] = min;
// }
// }
//希尔排序
// for(int gap = nums.length/2;gap > 0;gap /= 2){
// for(int i = gap;i < nums.length;i++){
// for(int j = i;j >= gap;j -= gap){
// if(nums[j-gap] > nums[j]){
// int temp = nums[j];
// nums[j] = nums[j-gap];
// nums[j-gap] = temp;
// }else{
// break;
// }
// }
// }
// }
//return nums;
通过该题练习数组排序的几种算法。
低级排序:冒泡排序,插入排序,选择排序。
高级排序:希尔排序,归并排序,快速排序,基数排序(桶排序)。
2.找出数组中重复的数字
解法一:先排序,后遍历数组(最麻烦的操作)
public int findRepeatNumber(int[] nums) {
//先排序,后找重复数字
// for(int N = nums.length/2;N > 0;N /= 2){
// for(int i = N;i <nums.length;i++){
// for(int j = i-N;j >=0;j--){
// if(nums[j] > nums[j+N]){
// int temp = nums[j+N];
// nums[j+N] = nums[j];
// nums[j] = temp;
// }else{
// break;
// }
// }
// }
// }
// for(int i = 0;i<nums.length-1;i++){
// if(nums[i] == nums[i+1]){
// return nums[i];
// }
// }
// return -1;
}
解法二:遍历数组,由于只需要找出数组中任意一个重复的数字,因此遍历数组,遇到重复的数字即返回。为了判断一个数字是否重复遇到,使用集合存储已经遇到的数字,如果遇到的一个数字已经在集合中,则当前的数字是重复数字。
// Set<Integer> set = new HashSet<Integer>();//Set存储不重复无序元素
// int repeat = -1;
// for (int num : nums) {
// if (!set.add(num)) {
// repeat = num;
// break;
// }
// }
// return repeat;
解法三:原地交换。题目说明尚未被充分使用,即 在一个长度为 n 的数组 nums 里的所有数字都在 0 ~ n-1 的范围内 。 此说明含义:数组元素的 索引 和 值 是 一对多 的关系。
因此,可遍历数组并通过交换操作,使元素的 索引 与 值 一一对应(即 nums[i] = inums[i]=i )。因而,就能通过索引映射对应的值,起到与字典等价的作用。
遍历中,第一次遇到数字 xx 时,将其交换至索引 xx 处;而当第二次遇到数字 xx 时,一定有 nums[x] = xnums[x]=x ,此时即可得到一组重复数字。
算法流程:
遍历数组 numsnums ,设索引初始值为 i = 0 :若 nums[i] = inums[i]=i : 说明此数字已在对应索引位置,无需交换,因此跳过;
若 nums[nums[i]] = nums[i]: 代表索引 nums[i]处和索引 i 处的元素值都为 nums[i] ,即找到一组重复值,返回此值 nums[i] ;
否则: 交换索引为 i 和 nums[i] 的元素值,将此数字交换至对应索引位置。
若遍历完毕尚未返回,则返回 -1−1 。复杂度分析:
时间复杂度 O(N) : 遍历数组使用 O(N) ,每轮遍历的判断和交换操作使用 O(1) 。
空间复杂度 O(1) : 使用常数复杂度的额外空间。
int i = 0;
while(i < nums.length) {
if(nums[i] == i) {
i++;
continue;
}
if(nums[nums[i]] == nums[i]) return nums[i];
int tmp = nums[i];
nums[i] = nums[tmp];
nums[tmp] = tmp;
}
return -1;
3.二维数组的查找
解法一:暴力求解,遍历数组。
解法二:线性查找。暴力法未利用矩阵 “从上到下递增、从左到右递增” 的特点,显然不是最优解法。如下图所示,我们将矩阵逆时针旋转 45° ,并将其转化为图形式,发现其类似于 二叉搜索树 ,即对于每个元素,其左分支元素更小、右分支元素更大。因此,通过从 “根节点” 开始搜索,遇到比 target 大的元素就向左,反之向右,即可找到目标值 target 。
int i = matrix.length - 1, j = 0;
while(i >= 0 && j < matrix[0].length)
{
if(matrix[i][j] > target) i--;
else if(matrix[i][j] < target) j++;
else return true;
}
return false;
4.在排序数组中查找指定数字
排序数组中的搜索问题,首先想到 二分法 解决
排序数组 nums中的所有数字 target形成一个窗口,记窗口的 左 / 右边界 索引分别为 left和 right ,分别对应窗口左边 / 右边的首个元素。
本题要求统计数字 target 的出现次数,可转化为:使用二分法分别找到 左边界 left和 右边界 right ,易得数字 target 的数量为 right - left - 1。
// 搜索右边界 right
int i = 0, j = nums.length - 1;
while(i <= j) {
int m = (i + j) / 2;
if(nums[m] <= target) i = m + 1;
else j = m - 1;
}
int right = i;
// 若数组中无 target ,则提前返回
if(j >= 0 && nums[j] != target) return 0;
// 搜索左边界 right
i = 0; j = nums.length - 1;
while(i <= j) {
int m = (i + j) / 2;
if(nums[m] < target) i = m + 1;
else j = m - 1;
}
int left = j;
return right - left - 1;
关于二分法的详细使用步骤,可以看这里:https://leetcode-cn.com/problems/search-insert-position/solution/te-bie-hao-yong-de-er-fen-cha-fa-fa-mo-ban-python-/