3.数组中重复的数字
**题目描述:**在一个长度为n的数组里的所有数字都在0到n-1的范围内。数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复几次。请找出数组中任意一个重复的数字。例如
Input:
{2, 3, 1, 0, 2, 5}
Output:
2
因为数组中的数字都在0~n-1的范围内,所以,如果数组中没有重复的数,那当数组排序后,数字i将出现在下标为i的位置。现在我们重排这个数组,从头到尾扫描每个数字,当扫描到下标为i的数字时,首先比较这个数字(记为m)是不是等于i。如果是,则接着扫描下一个数字;如果不是,则再拿它和m 位置上的数字进行比较,如果它们相等,就找到了一个重复的数字(该数字在下标为i和m的位置都出现了),返回true;如果它和m位置上的数字不相等,就把第i个数字和第m个数字交换,把m放到属于它的位置。接下来再继续循环,直到最后还没找到认为没找到重复元素,返回false。
public boolean duplication(int[] numbers, int length, int[] duplication){
//如果输入的数组为空,直接返回false
if(numbers == null || length<=0)
return false;
//从头到尾扫描数组
for(int i=0; i<length; i++){
//如果数组不在1——n-1的范围内,直接返回false
if(numbers[i]<0 || numbers[i]>=length)
return false;
//当数组中某个元素不等于其下标时,分为两种情况
while(numbers[i]!=i){
//如果这个元素与以这个元素值为下标的元素相等(元素本应该在的位置),则说明这个元素重复了
if(numbers[i] == numbers[numbers[i]]){
//把这个重复的元素存储在duplication[]数组中
duplication[0] = numbers[i];
return true;
}else{ //若不相等,即交换,把元素放到与下标对应的位置
int temp = numbers[i];
numbers[i] = numbers[temp];
numbers[temp] = temp;
}
}
}
return false;
}
加入Scanner:
import java.util.Scanner;
public class Test {
public static void getRepeateNum( int[] num) {
int NumChange;
System.out.println("重复数字是:");
for(int index = 0; index < num.length; index++) {
while(num[index] != index) {
if(num[index] == num[num[index]]) {
System.out.print(num[index]+" ");
break;
} else {
NumChange = num[num[index]];
num[num[index]] = num[index];
num[index] = NumChange;
}
}
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int[] num = new int[5]; //数组长度可以自己定义
System.out.println("请输入一组数据:");
for(int i = 0; i < 5; i++) {
num[i] = scanner.nextInt();
}
getRepeateNum(num);
}
}
利用HashMap
class Solution {
public int findRepeatNumber(int[] nums) {
if(nums==null||nums.length<=0){
return 0;
}
HashMap<Integer,Integer> map=new HashMap<>();
for(int i=0;i<nums.length;i++){
if(!map.containsKey(nums[i])){
map.put(nums[i],1);
}else{
int count=map.get(nums[i]);
map.put(nums[i],++count);
}
int times=map.get(nums[i]);
if(times>1){
return nums[i];
}
}return 0;
}
}
4.二维数组中的查找
**题目描述:**在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
选择从左下角开始搜寻,因为选择在左下角搜寻的话,如果目标值大于搜索值,那么就向右继续搜索,如果目标值小于搜索值,那么就向上继续搜索。可以根据target和当前元素的大小关系来缩小查找区间
public class Test {
public boolean Find(int target, int[][] matrix) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0){
return false;}
int rows = matrix.length;//定义多维数组的行数
cols = matrix[0].length;//定义多维数组的列数
int r = 0, c = cols - 1; //从右上角开始
while (r <= rows - 1 && c >= 0) {
if (target == matrix[r][c]){
return true;
}else if (target > matrix[r][c]){
r++;
}else{
c--;
}
return false;
}
public static void main(String[] args) {
Test test=new Test();
int[][] matrix={{1,2,3},{4,5,6},{7,8,9}};//测试一个三行三列的数组,目标值为5
System.out.println(test.Find(matrix, 5));
}
}
二维数组的声明:
声明同时赋值:
int[ ][ ] matrix={{1,2,3},{4,5,6},{7,8,9}};
二维数组的length()方法:
在二维数组中:
11.旋转数组的最小数字
**题目描述:**把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1
从头到尾遍历数组一次,找出最小的元素
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length==0){
return 0;
}
int ans=array[0];
for(int i=1;i<array.length;i++){
ans=Math.min(ans,array[i]);
}
return ans;
}
}
Math中的min方法是用来比较两个数大小的,返回较小的那个数值
旋转数组实际上可以划分为两个有序的子数组,最小的元素刚好是这两个字数组的分界线,故旋转数组找最小元素值也可以采取二分查找的思路。通过二分查找,不断更新存在于两个非递减的排序子数组的下标
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length==0){
return 0;
}
int left=0;
int right=array.length-1;
while(left<right-1){
int mid=(left+right)/2;
if(array[left]<=array[mid]){
left=mid; //说明mid所在位置是在第一个非递减子数组中
}else if(array[right]>=array[mid]){
right=mid; //说明mid所在位置是在第二个非递减子数组中
}
}return array[right];
}
}
21.调整数组顺序使奇数位于偶数前面
**题目描述:**输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变
类似于插入排序的思想,遇到奇数就将当前奇数向前移动,直到往前移动过程中遇到奇数时才停止移动。时间复杂度时O(n^2)
public class Solution {
public void reOrderArray(int [] array) {
for(int i=0;i<array.length;i++){
if(array[i]%2 != 0){
for(int j=i-1;j>=0;j--){ //遇到奇数向前移动
if(array[j]%2 == 0){
int temp=array[j];
array[j]=array[j+1];
array[j+1]=temp;
}else{
break;
}
}
}
}
}
}
可以开辟2个新空间分别存储奇数、偶数值,最后将2个空间的值合并即可,时间复杂度是O(n),但空间复杂度比方法一大
public class Solution {
public void reOrderArray(int [] array) {
int[] array1=new int[array.length]; //定义一个数组存放奇数
int[] array2=new int[array.length]; //定义一个数组存放偶数
int j=0,k=0; //两个新数组的下标
int length1=0,length2=0; //两个新数组的长度
for(int i=0;i<array.length;i++){
if(array[i]%2!=0){
array1[j++]=array[i]; //奇数存放到array1数组
length1++;
}else{
array2[k++]=array[i]; //偶数存放到array2数组
length2++;
}
}
for(int i=0;i<length1;i++){
array[i]=array1[i]; //奇数数组先放入原array数组中
}
for(int i=0;i<length2;i++){
array[length1+i]=array2[i]; //偶数数组后放入原array数组中
}
}
}
39.数组之数组中出现次数超过一半的数字
**题目描述:**数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0
使用Map集合
import java.util.*;
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
HashMap<Integer,Integer> map=new HashMap<>();
for(int i=0;i<array.length;i++){
if(!map.containsKey(array[i])){ //之前map中没出现过array[i],现在第一次出现,则K-V中V值赋值1
map.put(array[i],1);
}else{
int count=map.get(array[i]);
map.put(array[i],++count); //之前map中出现过array[i],则++count,
}
int time=map.get(array[i]);
if(time>array.length/2)
return array[i];
}
return 0;
}
}
i++是使用i之后再加1,++i是使用i之前先使i加一
import java.util.*;
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
HashMap<Integer,Integer> map=new HashMap<>(); //存储每个数字出现的次数
int target=0; //用来存储出现次数最多的数字
int sum=0; //用来存储出现次数最多的数字的出现次数
for(int i:array){
map.put(i,map.getOrDefault(i,0)+1); //更新当前位置数字出现的次数
if(sum<map.get(i)){
sum=map.get(i);
target=i;
}
}if(sum>array.length/2){
return target;
}return 0;
}
}
当Map集合中有这个key时,就获得这个key值对应的Value,如果没有就使用默认值defaultValue
42.连续子数组的最大和
**题目描述:**输入一个整形数组,数组里有正数也有负数。数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。求所有子数组的和的最大值。例如数组:arr[ ]={1, 2, 3, -2, 4, -3 } 最大子数组为 {1, 2, 3, -2, 4} 和为8
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
if(array==null||array.length<=0){
return 0;
}
int sum=0;
int Max=array[0]; //Max默认array的第一个元素
for(int i=0;i<array.length;i++){
sum += array[i]; // 这几行代码的过程就是:通过sum变量去统计当前连续子序列的和,
Max=Math.max(Max,sum); //统计完之后,更新Max的值,
if(sum<0){ //最后判断是否更新sum的值
sum=0;
}
}
return Max;
}
}
public class Solution{
public int FindGreatestSumOfSubArray(int[] array) {
int[] sum = new int[array.length]; // 用来去统计0-i位置的和
sum[0] = array[0];
for (int i = 1; i < array.length; i++) {
sum[i] = sum[i - 1] + array[i];
}
int Max = sum[0]; // 默认第一个元素
// i是终点,j是起点
for (int i = 0; i < array.length; i++) {
for (int j = 0; j <= i; j++) {
if (j == 0) {
Max = Math.max(Max, sum[i]); // 说明起点在0位置
} else {
Max = Math.max(Max, sum[i] - sum[j - 1]); // i-j的和就等于从起点到i位置之和减去从起点到j-1的位置之和
}
}
}
return Max;
}
45.把数组排成最小的数
**题目描述:**输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323
import java.util.*;
public class Solution {
public String PrintMinNumber(int [] numbers) {
if(numbers==null || numbers.length<=0)
return "";
ArrayList<String> list = new ArrayList<String>();
for(int number:numbers)
list.add(String.valueOf(number)); //将数组里的数字存放到 ArrayList里面
Collections.sort(list,new Comparator<String>(){
@Override
public int compare(String s1,String s2){
String a=s1+s2;
String b=s2+s1;
return a.compareTo(b);
}
});
StringBuilder ans= new StringBuilder();
for(String str:list)
ans.append(str);
return ans.toString();
}
}
将 int 变量 i 转换成字符串
在基本数据中,compareTo()是比较两个Character 对象;在 Boolean中,是用boolean的实例于其它实例进行比较;在String 中,则是按照字典顺序进行比较,返回的值是一个int 型
51.数组中的逆序对
**题目描述:**在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。例如,在数组{7,5,6,4}中,一共存在5个逆序对,分别是(7,5)、(7,6)、(7,4)、(5,4)、(6,4)
归并排序
53.数字在排序数组中出现的次数
**题目描述:**统计一个数字在排序数组中出现的次数。
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
建立一个HashMap,存放各个数字出现的次数,然后看map中是否存在k即可
import java.util.*;
public class Solution {
public int GetNumberOfK(int [] array , int k) {
java.util.HashMap<Integer,Integer> map=new HashMap<>();
for(int i=0;i<array.length;i++){
if(!map.containsKey(array[i])){
map.put(array[i],1);
}
else{
int t=map.get(array[i]);
map.put(array[i],t+1);
}
}
if(map.containsKey(k)){
return map.get(k);
}
return 0;
}
}
一般情况下,排序数组中的查找都可以通过二分查找来解决
通过二分查找查找k,分别找到第一次出现的位置和最后一次出现的索引位置。
通过k出现的第一和最后的位置直接计算出现次数即可,last - first +1。
public class Solution {
private int findFirstPosition(int[] array, int k) { //查找k的起点位置
int l = 0;
int r = array.length - 1;
while (l < r) {
int mid = (l + r) >> 1;
if (array[mid] == k) {
if(mid - 1 >= 0 && array[mid - 1] == k) {
// 说明mid当前的位置不是初始位置,k的初始位置是在l~mid-1区间
r = mid - 1;
} else {
// 就可以说明mid位置的数字就是k的初始位置
return mid;
}
} else if (array[mid] > k) {
r = mid - 1; // k是属于l~mid-1区间
} else {
l = mid + 1; // k是属于mid+1~r区间
}
}
return l;
}
private int findLastPosition(int[] array, int k) { //查找k的终点位置
int l = 0;
int r = array.length - 1;
while (l < r) {
int mid = (l + r) >> 1;
if (array[mid] == k) {
if(mid + 1 < array.length && array[mid + 1] == k) {
// 说明mid当前的位置不是终止位置,k的初始位置是在mid+1~r区间
l = mid + 1;
} else {
// 就可以说明mid位置的数字就是k的终止位置
return mid;
}
} else if (array[mid] > k) {
r = mid - 1; // k是属于l~mid-1区间
} else {
l = mid + 1; // k是属于mid+1~r区间
}
}
return l;
}
public int GetNumberOfK(int [] array , int k) {
if (array.length == 0) {
return 0;
}
int firstPosition = findFirstPosition(array, k);
int lastPosition = findLastPosition(array, k);
if (array[firstPosition] != k) { //判断array里面是否存在k
return 0;
}
return lastPosition - firstPosition + 1;
}
}
56.数组中只出现一次的两个数字
**题目描述:**一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字
输入: nums = [2,4,3,6,3,2,5,5]
输出: [4,6]
66.构建乘积数组
**题目描述:**给定一个数组 A[0,1,…,n-1],请构建一个数组 B[0,1,…,n-1],其中 B 中的元素 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。
这道题就是要求结果数组上的每一个数,都是原数组除了这个位置的数的乘积;
先把每一个元素的左边的乘积和右边的乘积都算出来,然后新的数组的元素就等于这个元素左边的乘积加上右边的乘积;
public class Solution {
public static int[] multiply(int[] A) {
int[] f1 = new int[A.length]; // 0到i-1的乘积
int[] f2 = new int[A.length]; // i+1到n-1的乘积
int ans1 = 1; // 0-(i-1)的乘积
int ans2 = 1; // (i+1)-n-1的乘积
for (int i = 0, j = A.length - 1; i < A.length; i++, j--) {
f1[i] = ans1;
ans1 *= A[i];
f2[j] = ans2;
ans2 *= A[j];
}
int[] B = new int[A.length];
for (int i = 0; i < A.length; i++) {
B[i] = f1[i] * f2[i];
}
return B;
}
}