目录
一、剑指offer(一)二维数组中的查找
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
/* 思路
* 矩阵是有序的,从左下角来看,向上数字递减,向右数字递增,
* 因此从左下角开始查找,当要查找数字比左下角数字大时。右移
* 要查找数字比左下角数字小时,上移
*/
public class Solution {
public boolean Find(int target, int [][] array) {
//定义二维数组的长度和深度
int deep=array.length;
int length=array[0].length;
//定义长度和深度的下标
int i=deep-1;
int j=0;
//方法,选择最左下角的元素arr[i][j],若targrt>该元素,右移;若target<该元素则上移
while(i>=0&&j<=length-1){
int element=array[i][j];
if(target==element){return true;}
else if(target>element){
j++;
}
else if(target<element){
i--;
}
}
return false;
}
}
二、剑指offer(三十)连续子数组的最大和
连续子数组的最大和
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。
今天测试组开完会后,他又发话了:在古老的一维模式识别中,
常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。
但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?
例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。
给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
int len=array.length;
int res=Integer.MIN_VALUE;
for(int i=0;i<len-1;i++){
int max=array[i];
for(int j=i+1;j<len;j++){
res=Math.max(max,res);
max+=array[j];
}
res=Math.max(max,res);
}
return res;
}
}
三、剑指offer(三十四)第一次只出现一次的字符
1.题目描述
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).
2.分析:
1.遍历str,把字符存进一个数组中,数组下标和字符ASCII码相关 ,值代表频次。
2.再遍历一遍str,去数组中查找相对应的频次如何,如果=1,则返回,此时就是第一个只出现一次的字符。
public class Solution {
public int FirstNotRepeatingChar(String str) {
//a-z:65~90 A-Z:97~122 所以a~Z:共65位
int [] arr = new int[65];
for (int i=0;i<str.length();i++){
int index=(int)str.charAt(i)-65;
if (arr[index]==0)arr[index]=1;
else arr[index]++;
}
for (int j=0;j<str.length();j++){
int index=(int)str.charAt(j)-65;
if (arr[index]==1)return j;
}
return -1;
}
}
四、剑指offer(三十五):数组中的逆序对
1.题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5
示例1
输入
复制
1,2,3,4,5,6,7,0
输出
复制
7
/**
* 2.分析:使用归并排序:https://blog.csdn.net/qq_37768971/article/details/88777334
* 1.arr[i]<arr[j],不存在逆序对
* 2.arr[i]>arr[j],逆序对数量增加:mid+1-i
*/
/**
* [2,6,4,1]
* [2,6][4,1]
* [2][6][4][1]
* ————————————————————————
* [2,6][1,4] ->[2,6][*,4]
* [1,*,*,*]
* ————————————————————————
* [2,6][*,4] ->[*,6][*,4]
* [1,2,*,*]
* ————————————————————————
* [*,6][*,4] ->[*,6][*,*]
* [1,2,4,*]
* ————————————————————————
* [*,6][*,*] ->[*,*][*,*]
* [1,2,4,6]
*/
public class Sword35_InversePairs {
int count;
public int InversePairs(int [] array) {
count=0;
int len = array.length;
if (len==0)return 0;
mergeSort(array,0,len-1);
return count;
}
public void mergeSort(int [] arr , int start , int end ){
if (start>=end)return;
int div=start+(end-start)/2;
mergeSort(arr,start,div);
mergeSort(arr,div+1,end);
merge(arr,start,end,div);
}
public void merge(int [] arr , int start , int end , int div){
int len=end-start+1;
int [] copy = new int[len];
for(int i=0;i<len;i++){
copy[i]=arr[i+start];
}
int lt = 0;
int rt =div-start+1;
int et = lt+end-start;
//一定要注意lt和rt是动态的,如果需要判断一些固定的东西,不能用!!!
for (int i=lt;i<=et;i++){
//此处是lt>div-start,不是lt>rt
if (lt>div-start){
arr[start+i]=copy[rt];
rt++;
}
//et是固定的可以用
else if (rt>et){
arr[start+i]=copy[lt];
lt++;
}
//注意此处是 div-start+1 而不是rt,因为rt是在变化的
else if (copy[div-start+1]>=copy[div-start])break;//此处为优化
else if (copy[lt]<=copy[rt]){
arr[start+i]=copy[lt];
lt++;
}
else {
//结果也是用的固定值,而不是rt,所以是(div-start+1)-lt,即右边第一个位置-lt;
count=(count+div-start+1-lt)%1000000007;//注意此处要%,否则会出错
arr[start+i]=copy[rt];
rt++;
}
}
}
public static void main(String[] args) {
Sword35_InversePairs s35 = new Sword35_InversePairs();
int arr[]={364,637,341,406,747,995,234,971,571,219,993,407,416,366,315,301,601,650,418,355,460,505,360,965,516,648,727,667,465,849,455,181,486,149,588,233,144,174,557,67,746,550,474,162,268,142,463,221,882,576,604,739,288,569,256,936,275,401,497,82,935,983,583,523,697,478,147,795,380,973,958,115,773,870,259,655,446,863,735,784,3,671,433,630,425,930,64,266,235,187,284,665,874,80,45,848,38,811,267,575};
// s35.mergeSort(arr,0,arr.length-1);
// System.out.print(arr);
// int arr[] = {64,637,341,406,747,995,234,971,571,219,993,407,416,366,315,301,601,650,418,355,460,505,360,965,516,648,727};
int count=s35.InversePairs(arr);
System.out.print(count);
System.out.println(arr);
}
}
//自己的解法:O(N^2):会超时
//public class Sword35_InversePairs {
// public int InversePairs(int [] array) {
// int len = array.length;
// int count = 0;
// for(int i=len-1;i>0;i--){
// for(int j=i-1;j>=0;j--){
// if(array[i]<array[j])
// count++;
// }
// }
// return count%1000000007;
// }
//
// public static void main(String[] args) {
// Sword35_InversePairs s35 = new Sword35_InversePairs();
// int arr[] = {1,2,3,4,5,6,7,0};
// int res=s35.InversePairs(arr);
// System.out.print(res);
// }
//}
五、剑指offer(三十七):数字在排序数组中出现的次数
1、题目描述
统计一个数字在排序数组中出现的次数。
public class Solution {
public int GetNumberOfK(int [] array , int k) {
int len = array.length;
int count = 0;
for(int i=0;i<len;i++){
if(array[i]>k)break;
if(array[i]==k)count++;
}
return count;
}
}
public class Sword35_InversePairs {
int count;
public int InversePairs(int [] array) {
count=0;
int len = array.length;
if (len==0)return 0;
mergeSort(array,0,len-1);
return count;
}
public void mergeSort(int [] arr , int start , int end ){
if (start>=end)return;
int div=start+(end-start)/2;
mergeSort(arr,start,div);
mergeSort(arr,div+1,end);
merge(arr,start,end,div);
}
public void merge(int [] arr , int start , int end , int div){
int len=end-start+1;
int [] copy = new int[len];
for(int i=0;i<len;i++){
copy[i]=arr[i+start];
}
int lt = 0;
int rt =div-start+1;
int et = lt+end-start;
//一定要注意lt和rt是动态的,如果需要判断一些固定的东西,不能用!!!
for (int i=lt;i<=et;i++){
//此处是lt>div-start,不是lt>rt
if (lt>div-start){
arr[start+i]=copy[rt];
rt++;
}
//et是固定的可以用
else if (rt>et){
arr[start+i]=copy[lt];
lt++;
}
//注意此处是 div-start+1 而不是rt,因为rt是在变化的
else if (copy[div-start+1]>=copy[div-start])break;//此处为优化
else if (copy[lt]<=copy[rt]){
arr[start+i]=copy[lt];
lt++;
}
else {
//结果也是用的固定值,而不是rt,所以是(div-start+1)-lt,即右边第一个位置-lt;
count=(count+div-start+1-lt)%1000000007;//注意此处要%,否则会出错
arr[start+i]=copy[rt];
rt++;
}
}
}
public static void main(String[] args) {
Sword35_InversePairs s35 = new Sword35_InversePairs();
int arr[]={364,637,341,406,747,995,234,971,571,219,993,407,416,366,315,301,601,650,418,355,460,505,360,965,516,648,727,667,465,849,455,181,486,149,588,233,144,174,557,67,746,550,474,162,268,142,463,221,882,576,604,739,288,569,256,936,275,401,497,82,935,983,583,523,697,478,147,795,380,973,958,115,773,870,259,655,446,863,735,784,3,671,433,630,425,930,64,266,235,187,284,665,874,80,45,848,38,811,267,575};
// s35.mergeSort(arr,0,arr.length-1);
// System.out.print(arr);
// int arr[] = {64,637,341,406,747,995,234,971,571,219,993,407,416,366,315,301,601,650,418,355,460,505,360,965,516,648,727};
int count=s35.InversePairs(arr);
System.out.print(count);
System.out.println(arr);
}
}
//自己的解法:O(N^2):会超时
//public class Sword35_InversePairs {
// public int InversePairs(int [] array) {
// int len = array.length;
// int count = 0;
// for(int i=len-1;i>0;i--){
// for(int j=i-1;j>=0;j--){
// if(array[i]<array[j])
// count++;
// }
// }
// return count%1000000007;
// }
//
// public static void main(String[] args) {
// Sword35_InversePairs s35 = new Sword35_InversePairs();
// int arr[] = {1,2,3,4,5,6,7,0};
// int res=s35.InversePairs(arr);
// System.out.print(res);
// }
//}
六、剑指offer(四十)数组中只出现一次的数字:
题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
package IMUHERO;
import java.util.HashMap;
public class Solution40_FindNumsAppearOnce {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
int len = array.length;
HashMap<Integer,Integer> map=new HashMap<>();
for(int i=0;i<len;i++){
if(!map.containsKey(array[i])){
map.put(array[i],1);
}
else{
map.put(array[i],map.get(array[i])+1);
}
}
int [] num = new int[2];
int i=0;
for(int key:map.keySet()){
if (map.get(key)==1){
num[i]=key;
i++;
}
}
num1[0]=num[0];
num2[0]=num[1];
}
}
其他遍历方法:
for (Map.Entry<Integer,Integer>entry:map.entrySet()){
if (entry.getValue()==1){
num[i]=entry.getKey();
i++;
}
}
七、剑指offer(四十二)和为S的两个数
1.题目描述
输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
输出描述:
对应每个测试案例,输出两个数,小的先输出。
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
ArrayList<Integer>list=new ArrayList<>();
if(array.length==0)return list;
//双指针法:
int lt=0;//左指针
int rt=array.length-1;//右指针
while(lt<rt){
if(array[lt]+array[rt]<sum){
lt++;
}
else if(array[lt]+array[rt]>sum){
rt--;
}
else{
if (list.size()==0){
list.add(array[lt]);
list.add(array[rt]);
}
else if (array[lt]*array[rt]<list.get(0)*list.get(1)){
list.set(0,array[lt]);
list.set(1,array[rt]);
}
rt--;
}
}
return list;
}
}
八、剑指offer(四十五)扑克牌顺子
1.题目描述
LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。
2.分析:
1.先把数组排序,方便查看是否顺序
2.统计大小王数量count0 和 需要补的空缺数量count
(1)number[i] == 0 ,count0++;
(2)其他情况(不能越界):如果出现重复元素,直接无法组成,其他情况 count++
3.如果 count0>=count,表示可以组成顺序。
import java.util.Arrays;
public class Solution {
public boolean isContinuous(int [] numbers) {
Arrays.sort(numbers);
int len = numbers.length;
int count0 = 0; //大小王的数量
int count = 0; //需要用大小王来补的空缺数量
if(len==0)return false;
for(int i=0;i<len;i++){
if(numbers[i]==0){
count0++;
}
//不能出现重复元素,不能越界
else if(i<len-1){
//此条不包含等于0的情况,数字相等即表示不能构成顺子
if(numbers[i]==numbers[i+1]){
return false;
}
if(numbers[i+1]-numbers[i]>1){
count+=numbers[i+1]-numbers[i]-1;//需要插入的个数
}
}
}
if(count<=count0)return true;//如果大小王的数量比需要补的空缺还要多,表示可以组成顺子
else return false;
}
}
九、剑指offer(五十)第一个重复的数字
1.题目:在number[ ]数组中找出第一个重复的数字,如果存在,返回true,如果不存在,返回false
将重复的数字存入deplication[0]
package IMUHERO;
import java.util.HashSet;
public class Sword50_duplicated_number_in_array {
public boolean duplicate(int numbers[],int length,int [] duplication) {
HashSet<Integer>set = new HashSet<>();
for (int i=0;i<length;i++){
if (set.contains(numbers[i])){
duplication[0]=numbers[i];
return false;
}
else set.add(numbers[i]);
}
return true;
}
}