从旋转的有序数组中查找元素
问题描述:
给定一个排序和旋转的数组,如下所示:
int arr[]={16,19,21,25,3,5,8,10};
复制代码
该数组是从一个有序数组arr[]={3,5,8,10,16,19,21,25}
旋转后所得。
要求在在O(log n)
时间复杂度的数组中搜索到一个指定元素。
思路:
-
如果直接遍历数组,则时间复杂度为
O(n)
,不符合题目要求; -
因为数组是由有序数组旋转所得,所以在某个下标的之前和之后是有序的;
-
然后按照二分法查找。
算法逻辑:
-
计算出中位下标mid=(low+high)/2;
-
如果arr[mid]等于要查找的数字则返回;
-
如果[low…mid]是有序的;
-
如果要查找的数字在[low…mid],则high=mid-1;
-
如果要查找的数字不在[low…mid],则low=mid+1;
-
如果[mid…high]是有序的;
-
如果要查找的数字在[mid…high],则low=mid+1;
-
如果要查找的数字不在[mid…high],则high=mid-1;
代码实现:
public class SearchElementSortedAndRotatedArrayMain {
public static void main(String[] args) {
int arr[] = {16, 19, 21, 25, 3, 5, 8, 10};
System.out.println("Index of element 5 : " + findElementRotatedSortedArray(arr, 0, arr.length - 1, 5));
}
public static int findElementRotatedSortedArray(int[] arr, int low, int high, int number) {
int mid;
while (low <= high) {
mid = low + ((high - low) / 2);
if (arr[mid] == number) {
return mid;
}
if (arr[mid] <= arr[high]) {
// 右边部分是有序的
if (number > arr[mid] && number <= arr[high]) {
low = mid + 1;
} else {
high = mid - 1;
}
} else {
// 左边部分是有序的
if (arr[low] <= number && number < arr[mid]) {
high = mid - 1;
} else {
low = mid + 1;
}
}
}
return -1;
}
}
复制代码
找到有序旋转数组中的最小元素
问题描述:
有序旋转数组定义同上一题,例如:
int arr[]={16,19,21,25,3,5,8,10};
复制代码
同样要求时间复杂度为O(log n)
。
思路:
与上题类似,因数组可以拆分为前后两个有序数组,可以通过二分查找法的变体来完成;
-
计算出中位下标mid=(low+high)/2;
-
如果[mid…high]是有序的;
-
最小值在右边,high=mid;
-
否则最小值在左边,low= mid+1;
代码实现:
public class MinimumElementSortedAndRotatedArrayMain {
public static void main(String[] args) {
int arr[] = {16, 19, 21, 25, 3, 5, 8, 10};
System.out.println("Minimum element in the array : " + findMinimumElementRotatedSortedArray(arr, 0, arr.length - 1));
}
public static int findMinimumElementRotatedSortedArray(int[] arr, int low, int high) {
int mid;
while (low < high) {
mid = low + ((high - low) / 2);
if (arr[mid] < arr[high]) {
high = mid;
} else {
low = mid+1;
}
}
return arr[low];
}
}
复制代码
查找数组中第二大的与元素
问题描述:
给定一个旋转有序数组,如下所示:
int[] arr1={7,5,6,1,4,2};
复制代码
找出第二大的元素:6
思路:
可以对数组排序,然后返回数组中的倒数第二个元素,时间复杂度为O(nlogn)
。
-
定义最大值highest 和第二大值变量secondHighest
-
对数组进行遍历
-
如果当前元素大于最大值
-
将highest赋值给secondHighest
-
将当前元素赋值给highest
-
否则,如果当前元素大于secondHighest
-
将当前元素赋值给secondHighest
代码实现:
public class FindSecondLargestMain {
public static void main(String args[]) {
int[] arr1 = {7, 5, 6, 1, 4, 2};
int secondHighest = findSecondLargestNumberInTheArray(arr1);
System.out.println("Second largest element in the array : " + secondHighest);
}
public static int findSecondLargestNumberInTheArray(int array[]) {
int highest = Integer.MIN_VALUE;
int secondHighest = Integer.MIN_VALUE;
// 遍历数组
for (int i = 0; i < array.length; i++) {
// 如果当前值大于最大值
if (array[i] > highest) {
// 最大值赋值给第二大值
secondHighest = highest;
// 当前值赋值给最大值
highest = array[i];
} else if (array[i] > secondHighest && array[i] != highest)
// 将当前值赋值给第二大值
secondHighest = array[i];
}
return secondHighest;
}
}
复制代码
找出数组中出现奇数次的数
题目描述:
给定一个整数数组, 只有一个数字出现奇数次,其他数字都出现偶数次。 你需要找到奇数次出现的数字。 需要用O(n)时间复杂度和O(1)空间复杂度来解决它。
思路1:
暴力解法:使用两层循环,记录每个元素出现的次数,这种方法的时间复杂度为O(n^2),不是最优解。
思路2:
使用Hash,将数字作为key,出现的次数作为value,每当key重复时,value+1,这种解法的时间复杂度为O(n),但是空间复杂度也为O(n),不符合要求。
代码实现:
int getOddTimesElementHashing(int ar[]) {
int i;
HashMap<Integer, Integer> elements = new HashMap<Integer, Integer>();
for (i = 0; i < ar.length; i++) {
int element = ar[i];
if (elements.get(element) == null) {
elements.put(element, 1);
} else{
elements.put(element, elements.get(element) + 1);
}
}
for (Entry<Integer, Integer> entry : elements.entrySet()) {
if (entry.getValue() % 2 == 1) {
return entry.getKey();
}
}
return -1;
}
复制代码
思路3:
基于位运算异或操作。
异或运算:相同为0,不同为1。如a=1001,b=1010,则ab=0010,aa=0000。
按照题目描述,数组中只有1个数字出现奇数次,其他数字都是偶数次,则将所有数字异或运算后的结果就是出现奇数次的数字。
代码实现:
int getOddTimesElement(int arr[]) {
int i;
int result = 0;
for (i = 0; i < arr.length; i++) {
result = result ^ arr[i];
}
return result;
}
复制代码
该解法的时间复杂度为O(n)
;因为只使用了一个变量result
,所以空间复杂度为O(1)
。
计算火车站需要的最少站台数
题目描述:
给定两个数组,分别对应火车站车辆到达的时间和出站的时间,计算出火车站最少需要几个站台。
// 到达时刻表
arrival[] = {1:00, 1:40, 1:50, 2:00, 2:15, 4:00}
// 出站时刻表
departure[] = {1:10, 3:00, 2:20, 2:30, 3:15, 6:00}
// 最少需要的站台数 = 4
复制代码
思路1:
遍历两个数组,检查每个到达和出站的时间间隔有多少重叠。
这种方式的时间复杂度为O(n^2),不是最优解。
思路2:
使用归并排序的逻辑。
-
对到达和出发的数组进行排序;
-
因为到达和出站数量一样,则从两个数组中取出相同位置的元素比较时间大小;
-
如果到达时间早,则站台数加1;
-
如果出站时间早,则站台数减1;
-
在这个过程中记录最大的站台数;
-
最后返回最大站台数的值。
这种算法的时间复杂度为O(n*log n)。
代码实现:
public class TrainPlatformMain {
public static void main(String args[]) {
// arr[] = {1:00, 1:40, 1:50, 2:00, 2:15, 4:00}
// dep[] = {1:10, 3:00, 2:20, 2:30, 3:15, 6:00}
int arr[] = {100, 140, 150, 200, 215, 400};
int dep[] = {110, 300, 210, 230, 315, 600};
System.out.println(“最少需要的站台数 =” + findPlatformsRequiredForStation(arr, dep, arr.length));
}
static int findPlatformsRequiredForStation(int arr[], int dep[], int n) {
int platform_needed = 0, maxPlatforms = 0;
Arrays.sort(arr);
Arrays.sort(dep);
int i = 0, j = 0;
// 类似归并排序中的归并操作
while (i < n && j < n) {
if (arr[i] < dep[j]) {
platform_needed++;
i++;
if (platform_needed > maxPlatforms)
maxPlatforms = platform_needed;
} else {
platform_needed–;
j++;
}
}
return maxPlatforms;
}
}
复制代码
数组中最两数之和最接近0的两个数
题目描述:
一个数组中有一系列的正数和负数,找出数组中两数之和最接近0的两个数。
例如:
array[]={1,3,-5,7,8,20,-40,6};
// 和最接近0的两个数是 : -5 and 6
复制代码
思路1:
暴力解法:将所有数字两两求和,如果和的绝对值更小,则赋值记录两数的值。
这种方法的时间复杂度为O(n^2)
,不是最优解。
代码实现:
public static void findPairWithMinSumBruteForce(int arr[]) {
if (arr.length < 2)
return;
// 预设前两个数的和最接近于0
int minimumSum = arr[0] + arr[1];
int pair1stIndex = 0;
int pair2ndIndex = 1;
for (int i = 0; i < arr.length; i++) {
for (int j = i + 1; j < arr.length; j++) {
int tempSum = arr[i] + arr[j];
if (Math.abs(tempSum) < Math.abs(minimumSum)) {
pair1stIndex = i;
pair2ndIndex = j;
minimumSum = tempSum;
}
}
}
System.out.println(" 和最接近0的两个数是 : " + arr[pair1stIndex] + " " + arr[pair2ndIndex]);
}
复制代码
思路2:
-
对数组进行排序;
-
定义两个索引对应数组的开始位置l=0,一个在结束位置r=n-1;
-
按照l<r的条件循环
-
计算arr[l]+arr[r]的和sum
-
如果abs(sum)<abs(minSum),将l和r记录在最小的两个数组元素变量上;
-
如果sum>0,则sum要更接近0需要将大值往小移动,r–;
-
如果sum<0,则sum要更接近0需要将小值往大移动,l++。
代码实现:
public static void findPairWithMinSum(int arr[]) {
Arrays.sort(arr);
int sum = 0;
int minimumSum = Integer.MAX_VALUE;
int n = arr.length;
// left and right index variables
int l = 0, r = n - 1;
int minLeft = l, minRight = n - 1;
while (l < r) {
sum = arr[l] + arr[r];
// 如果abs(sum)<abs(minSum),将l和r记录在最小的两个数组元素变量上;
if (Math.abs(sum) < Math.abs(minimumSum)) {
minimumSum = sum;
minLeft = l;
minRight = r;
}
if (sum < 0)
l++;
else
r–;
}
System.out.println(" 和最接近0的两个数是 : " + arr[minLeft] + " " + arr[minRight]);
}
复制代码
该算法的时间复杂度为O(NLogN)
。
数组中最两数之和最接近X的两个数
该问题为上一题的进阶版,找出两数之和最接近X的数。
思路1:
暴力解法:两层循环,求和与最接近的数进行比较,如果更小则记录对应数字,时间复杂度为O(n^2),不是最优解。
思路2:
与上一题的区别在于该问题要对求和结果比较的值是指定的X,不是0,不能直接使用abs()函数的结果进行比较;那该如何处理呢?
可以通过将abs()结果减去X,则对应该问题的解法。
-
对数组进行排序;
-
定义两个索引对应数组的开始位置l=0,一个在结束位置r=n-1;
-
按照l<r的条件循环
-
计算
arr[l]+arr[r]-x
的结果diff -
如果abs(diff)<minDiff,将l和r记录在最小的两个数组元素变量上;
-
如果sum>x,则sum要更接近x需要将大值往小移动,r–;
-
如果sum<x,则sum要更接近x需要将小值往大移动,l++。
代码实现:
public static void findPairWithClosestToX(int arr[], int X) {
Arrays.sort(arr);
int minimumDiff = Integer.MAX_VALUE;
int n = arr.length;
int l = 0, r = n - 1;
int minLeft = l, minRight = n - 1;
while (l < r) {
int currentDiff = Math.abs(arr[l] + arr[r] - X);
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Java)
最后
分享一套我整理的面试干货,这份文档结合了我多年的面试官经验,站在面试官的角度来告诉你,面试官提的那些问题他最想听到你给他的回答是什么,分享出来帮助那些对前途感到迷茫的朋友。
面试经验技巧篇
- 经验技巧1 如何巧妙地回答面试官的问题
- 经验技巧2 如何回答技术性的问题
- 经验技巧3 如何回答非技术性问题
- 经验技巧4 如何回答快速估算类问题
- 经验技巧5 如何回答算法设计问题
- 经验技巧6 如何回答系统设计题
- 经验技巧7 如何解决求职中的时间冲突问题
- 经验技巧8 如果面试问题曾经遇见过,是否要告知面试官
- 经验技巧9 在被企业拒绝后是否可以再申请
- 经验技巧10 如何应对自己不会回答的问题
- 经验技巧11 如何应对面试官的“激将法”语言
- 经验技巧12 如何处理与面试官持不同观点这个问题
- 经验技巧13 什么是职场暗语
面试真题篇
- 真题详解1 某知名互联网下载服务提供商软件工程师笔试题
- 真题详解2 某知名社交平台软件工程师笔试题
- 真题详解3 某知名安全软件服务提供商软件工程师笔试题
- 真题详解4 某知名互联网金融企业软件工程师笔试题
- 真题详解5 某知名搜索引擎提供商软件工程师笔试题
- 真题详解6 某初创公司软件工程师笔试题
- 真题详解7 某知名游戏软件开发公司软件工程师笔试题
- 真题详解8 某知名电子商务公司软件工程师笔试题
- 真题详解9 某顶级生活消费类网站软件工程师笔试题
- 真题详解10 某知名门户网站软件工程师笔试题
- 真题详解11 某知名互联网金融企业软件工程师笔试题
- 真题详解12 国内某知名网络设备提供商软件工程师笔试题
- 真题详解13 国内某顶级手机制造商软件工程师笔试题
- 真题详解14 某顶级大数据综合服务提供商软件工程师笔试题
- 真题详解15 某著名社交类上市公司软件工程师笔试题
- 真题详解16 某知名互联网公司软件工程师笔试题
- 真题详解17 某知名网络安全公司校园招聘技术类笔试题
- 真题详解18 某知名互联网游戏公司校园招聘运维开发岗笔试题
资料整理不易,点个关注再走吧
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
如何回答系统设计题
- 经验技巧7 如何解决求职中的时间冲突问题
- 经验技巧8 如果面试问题曾经遇见过,是否要告知面试官
- 经验技巧9 在被企业拒绝后是否可以再申请
- 经验技巧10 如何应对自己不会回答的问题
- 经验技巧11 如何应对面试官的“激将法”语言
- 经验技巧12 如何处理与面试官持不同观点这个问题
- 经验技巧13 什么是职场暗语
[外链图片转存中…(img-cZAqKNm7-1713812130940)]
面试真题篇
- 真题详解1 某知名互联网下载服务提供商软件工程师笔试题
- 真题详解2 某知名社交平台软件工程师笔试题
- 真题详解3 某知名安全软件服务提供商软件工程师笔试题
- 真题详解4 某知名互联网金融企业软件工程师笔试题
- 真题详解5 某知名搜索引擎提供商软件工程师笔试题
- 真题详解6 某初创公司软件工程师笔试题
- 真题详解7 某知名游戏软件开发公司软件工程师笔试题
- 真题详解8 某知名电子商务公司软件工程师笔试题
- 真题详解9 某顶级生活消费类网站软件工程师笔试题
- 真题详解10 某知名门户网站软件工程师笔试题
- 真题详解11 某知名互联网金融企业软件工程师笔试题
- 真题详解12 国内某知名网络设备提供商软件工程师笔试题
- 真题详解13 国内某顶级手机制造商软件工程师笔试题
- 真题详解14 某顶级大数据综合服务提供商软件工程师笔试题
- 真题详解15 某著名社交类上市公司软件工程师笔试题
- 真题详解16 某知名互联网公司软件工程师笔试题
- 真题详解17 某知名网络安全公司校园招聘技术类笔试题
- 真题详解18 某知名互联网游戏公司校园招聘运维开发岗笔试题
[外链图片转存中…(img-grmu1FPs-1713812130941)]
资料整理不易,点个关注再走吧
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!