Java分治算法题目练习(快速/归并排序)

Java分治算法题目练习(快速/归并排序)

分治算法

使用快速排序和归并排序进行解决问题,因为这两个都是采用归并的思想

颜色分类

在这里插入图片描述
题目解析:将其数组中0放在左边,1放在中间,2放在右边
在双指针算法中有一个移动零的题目,就是将所有0元素移动到右边,但是非0元素相对位置不改变
那题使用双指针将其数组分为三部分,因此这题也可以将其数组分块
left表示为0区域最右侧,i遍历数组,right表示2区域最左侧
使用这三个指针将这个数组分为了4部分
在这里插入图片描述
在这里插入图片描述


在这里插入图片描述
classSolution{publicvoidsortColors(int[] nums){//可以将其数组分为三部分//[0,left]:全是0//[left+1,i-1]全都是1//[i,right-1]待扫描//[right,n-1]全是2int left =-1;int i =0;int right = nums.length;while(i < right){if(nums[i]==0){swap(nums,++left,i++);}elseif(nums[i]==1){ i++;}else{swap(nums,--right,i);//此时会将right-1元素放到i下标,但是这个元素没有扫描过,所以这里不可以让i++}}}publicvoidswap(int[] nums,int i ,int j){int tem = nums[i]; nums[i]= nums[j]; nums[j]= tem;}}
时间复杂度:O(n)
空间复杂度:O(1)

排序数组(快排)

在这里插入图片描述
题目解析:给一个数组让我们排序
分治:使用快速排序,找一个key基准值,根据基准值,让其数组变成三个模块,左边模块<key,中间模块=key,右边模块>key,这时候在对左右两边的模块,分别进行找基准值进行排序,左右两边每一个模块又可以分为这三个部分,就这样不断排序最终结果就变成有序的了
key基准值如何取
这里采用随机取,随机其对应区间下标 r = new Random().nextInt( right - left + 1) + left,这样整个下标区间的取值就是[left,right]了
在这里插入图片描述


在这里插入图片描述
classSolution{publicint[]sortArray(int[] nums){qsort(nums,0,nums.length-1);return nums;}publicvoidqsort(int[] nums,int l,int r){if(l >= r){return;}//这里采用随机获取key//随机的下标是[l,r];int key = nums[newRandom().nextInt(r - l +1)+ l];//这里根据key将其数组分三块进行排序int left = l -1;int right = r +1;int i = l;while(i < right){if(nums[i]< key){swap(nums,++left,i++);}elseif(nums[i]== key){ i++;}else{swap(nums,--right,i);}}qsort(nums,l,left);qsort(nums,right,r);}publicvoidswap(int[] nums,int i,int j){int tem = nums[i]; nums[i]= nums[j]; nums[j]= tem;}}

数组中第K个最大元素

在这里插入图片描述
题目解析:给了一个数组,找出其中第K个大的元素
快速排序,根据上一题的快速排序,这里我们仍然使用快排,但是这里不一样的是,快速排序以后将数组分为三个模块,这里我们可以判断其第K个大的元素在那个模块,此时我们根据其每一个模块元素个数进行判断,在一个模块中,只需要在这一个模块中找即可剩下的两个模块就不用管了
在这里插入图片描述
classSolution{publicintfindKthLargest(int[] nums,int k){returnqsort(nums,0,nums.length-1,k);}publicintqsort(int[] nums,int l,int r,int k){if(l == r){return nums[l];}int key = nums[newRandom().nextInt(r - l +1)+l];int left = l -1;int right = r +1;int i = l;while(i < right){if(nums[i]< key){swap(nums,++left,i++);}elseif(nums[i]== key){ i++;}else{swap(nums,--right,i);}}//这里将其分为了[l,left] [left+1,right-1] [right,r]//判断其第k大的元素在那个模块int b = right - left -1;int c = r - right +1;if(c >= k){//只在右边找即可returnqsort(nums,right,r,k);}elseif((b+c)>=k){return key;}else{returnqsort(nums,l,left,k-b-c);}}publicvoidswap(int[] nums,int i,int j){int tem = nums[i]; nums[i]= nums[j]; nums[j]= tem;}}

最小的K个数

在这里插入图片描述
题目解析:返回数组中最小的k个数
快速选择算法 + 随机获取key值
这题和上一题找出第k个最大的数类似,唯一不同的就是排序后三个模块如果处理,因为这里最小的k个数顺序是随机的,也是每次只需要调整一个模块即可,剩下的两个模块不用管了
在这里插入图片描述
classSolution{publicint[]smallestK(int[] arr,int k){//快速选择算法qsort(arr,0,arr.length-1,k);int[] ret =newint[k];for(int i =0;i < k;i++){ ret[i]= arr[i];}return ret;}publicvoidqsort(int[] arr,int l ,int r ,int k){if(l >= r){return;}int key = arr[newRandom().nextInt(r - l +1)+ l];int left = l -1;int right = r +1;int i = l;while(i < right){if(arr[i]< key){swap(arr,++left,i++);}elseif(arr[i]== key){ i++;}else{swap(arr,--right,i);}}//[l,left] [left + 1, right - 1],[right , r]int a = left - l +1;int b = right - left -1;if(a > k){qsort(arr,l,left,k);}elseif(a+b >= k){return;}else{qsort(arr,right,r,k-a-b);}}publicvoidswap(int[] arr,int i,int j){int tem = arr[i]; arr[i]= arr[j]; arr[j]= tem;}}
时间复杂度:O(n),因为随机存取key,所以渐进O(n)
空间复杂度:O(k)

排序数组(归并)

在这里插入图片描述
题目解析:排序
这里仍然是归并的思想,根据mid将其数组分为左右两部分,左右两部分分别进行排序,左边部分又可以分为左右两部分,右边同理,当左右两边分完以后,就可以进行合并,左边先合并,右边再合并,最后合并到一起,最终整个数组再进行一次排序即可
在这里插入图片描述


归并排序详细介绍

在这里插入图片描述
classSolution{int[] tem;publicint[]sortArray(int[] nums){ tem =newint[nums.length];//归并排序mergeSort(nums,0,nums.length-1);return nums;}publicvoidmergeSort(int[] nums,int left ,int right){if(left >= right){return;}//根据中间点进行划分int mid =(left + right)/2;//左右两边分别进行排序mergeSort(nums,left,mid);mergeSort(nums,mid+1,right);//int[] tem = new int[right - left + 1];//合并两个有序数组int cur1 = left;int cur2 = mid+1;int i =0;while(cur1 <= mid && cur2 <= right){ tem[i++]= nums[cur1]>= nums[cur2]? nums[cur2++]: nums[cur1++];}//处理还没有遍历完的数组while(cur1 <= mid){ tem[i++]= nums[cur1++];}while(cur2 <= right){ tem[i++]= nums[cur2++];}//将排好序的数组放回去for(int j = left;j <= right;j++){ nums[j]= tem[j - left];}}}

交易逆序对的总数

在这里插入图片描述
题目解析:相对顺序不变,找出ai > aj , i < j,这样逆序对的总个数
算法原理:仍然采用分治的思想,采用
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述
//升序classSolution{int[] tem;publicintreversePairs(int[]record){ tem =newint[record.length];//归并排序returnmergeSort(record,0,record.length-1);}publicintmergeSort(int[]record,int left,int right){if(left >= right){return0;}//根据中间点进行划分int mid =(left + right)/2;//左右两边统计分别进行排序int ret =mergeSort(record, left, mid)+mergeSort(record, mid +1, right);//int[] tem = new int[right - left + 1];//一左一右的个数+排序//合并两个有序数组int cur1 = left;int cur2 = mid +1;int i =0;while(cur1 <= mid && cur2 <= right){if(record[cur1]<=record[cur2]){//cur1向后走,此时没有 tem[i++]=record[cur1++];}else{ ret += mid - cur1 +1; tem[i++]=record[cur2++];}}//处理还没有遍历完的数组while(cur1 <= mid){ tem[i++]=record[cur1++];}while(cur2 <= right){ tem[i++]=record[cur2++];}//将排好序的数组放回去for(int j = left; j <= right; j++){record[j]= tem[j - left];}return ret;}}
//降序classSolution{//降序就是找后面又几个数比我小int[] tem;publicintreversePairs(int[]record){ tem =newint[record.length];//归并排序returnmergeSort(record,0,record.length-1);}publicintmergeSort(int[]record,int left,int right){if(left >= right){return0;}//根据中间点进行划分int mid =(left + right)/2;//左右两边统计分别进行排序int ret =mergeSort(record, left, mid)+mergeSort(record, mid +1, right);//int[] tem = new int[right - left + 1];//一左一右的个数+排序//合并两个有序数组int cur1 = left;int cur2 = mid +1;int i =0;while(cur1 <= mid && cur2 <= right){if(record[cur1]<=record[cur2]){//cur1向后走,此时没有 tem[i++]=record[cur2++];}else{ ret += right - cur2 +1; tem[i++]=record[cur1++];}}//处理还没有遍历完的数组while(cur1 <= mid){ tem[i++]=record[cur1++];}while(cur2 <= right){ tem[i++]=record[cur2++];}//将排好序的数组放回去for(int j = left; j <= right; j++){record[j]= tem[j - left];}return ret;}}

翻转对

在这里插入图片描述
题目解析:找出前面一个元素大于后面元素2倍的总个数
归并:此题目和上题一样,只不过这里变成了2倍,上面我们将更新结果和合并数组放到一起,这里我们因为条件不同,所以要将其分分开写即可
在这里插入图片描述
这里2倍可能会溢出,因此直接让前一个数 / 2.0进行比较即可
//降序classSolution{int[] tem;publicintreversePairs(int[] nums){int n = nums.length; tem =newint[n];returnmergeSort(nums,0,n-1);}publicintmergeSort(int[] nums,int left,int right){if(left >= right){return0;}int ret =0;int mid =(left + right)/2; ret +=mergeSort(nums,left,mid); ret +=mergeSort(nums,mid+1,right);//先计算翻转对的个数int cur1 = left;int cur2 = mid+1;//降序while(cur1 <= mid){while(cur2 <= right && nums[cur1]/2.0<= nums[cur2]){ cur2++;}if(cur2 > right){break;}//更新结果 ret += right - cur2 +1; cur1++;}//合并两个有序数组 cur1 = left; cur2 = mid+1;int i = left;while(cur1 <= mid && cur2<=right){ tem[i++]= nums[cur1]>= nums[cur2]? nums[cur1++]: nums[cur2++];}//处理剩余while(cur1 <= mid){ tem[i++]= nums[cur1++];}while(cur2 <= right){ tem[i++]= nums[cur2++];}for(int j = left;j <= right;j++){ nums[j]= tem[j];}return ret;}}
//升序classSolution{int[] tem;publicintreversePairs(int[] nums){int n = nums.length; tem =newint[n];returnmergeSort(nums,0,n-1);}publicintmergeSort(int[] nums,int left,int right){if(left >= right){return0;}int ret =0;int mid =(left + right)/2; ret +=mergeSort(nums,left,mid); ret +=mergeSort(nums,mid+1,right);//先计算翻转对的个数int cur1 = left;int cur2 = mid+1;//降序while(cur2 <= right){while(cur1 <= mid && nums[cur1]/2.0<= nums[cur2]){ cur1++;}if(cur1 > mid){break;}//更新结果 ret += mid - cur1 +1; cur2++;}//合并两个有序数组 cur1 = left; cur2 = mid+1;int i = left;while(cur1 <= mid && cur2<=right){ tem[i++]= nums[cur1]>= nums[cur2]? nums[cur2++]: nums[cur1++];}//处理剩余while(cur1 <= mid){ tem[i++]= nums[cur1++];}while(cur2 <= right){ tem[i++]= nums[cur2++];}for(int j = left;j <= right;j++){ nums[j]= tem[j];}return ret;}}

计算右侧小于当前元素的个数

在这里插入图片描述
题目解析:返回一个新数组,对应下标的值是后面元素比当前下标元素小的个数
归并:这一题和上面一题非常类似,但是唯一问题,就是我们不断排序,不断更新结果,然而我们找不到其原本下标进行更新结果,因此这里我们就需要使用一个index数组进行存放原本下标,因此也需要一个临时数组存放临时下标
在这里插入图片描述
classSolution{int[] ret;//返回结果int[] index;//对应下标int[] temIndex;int[] temNums;publicList<Integer>countSmaller(int[] nums){int n = nums.length; ret =newint[n]; index =newint[n]; temIndex =newint[n]; temNums =newint[n];//初始化对应下标for(int i =0; i < n; i++){ index[i]= i;}mergeSort(nums,0, n -1);List<Integer> l =newArrayList<>();for(int x : ret){ l.add(x);}return l;}publicvoidmergeSort(int[] nums,int left,int right){if(left >= right){return;}int mid =(left + right)/2;mergeSort(nums, left, mid);mergeSort(nums, mid +1, right);int cur1 = left;int cur2 = mid +1;int i =0;//进行排序while(cur1 <= mid && cur2 <= right){//降序if(nums[cur1]<= nums[cur2]){ temNums[i]= nums[cur2];//这里要注意对应下标移动 temIndex[i++]= index[cur2++];}else{//更新结果,此时找到cur1对应的下标进行赋值 ret[index[cur1]]+= right - cur2 +1; temNums[i]= nums[cur1]; temIndex[i++]= index[cur1++];//更新下标}}//剩余进行排序while(cur1 <= mid){ temNums[i]= nums[cur1]; temIndex[i++]= index[cur1++];}while(cur2 <= right){ temNums[i]= nums[cur2]; temIndex[i++]= index[cur2++];}//合并for(int j = left; j <= right; j++){ nums[j]= temNums[j - left];//下标也要更新 index[j]= temIndex[j - left];}}}

Read more

当OpenClaw引爆全网,谁来解决企业AI Agent的“落地焦虑”?

当OpenClaw引爆全网,谁来解决企业AI Agent的“落地焦虑”?

2026 年 3 月,开源 AI Agent 框架 OpenClaw 在 GitHub 上的星标突破28万,并一度超越 React,成为 GitHub 最受关注的软件项目之一。短时间内,开发者利用它构建了大量实验性应用:从全栈开发辅助,到自动化营销脚本,再到桌面操作自动化,AI Agent 的能力边界正在迅速被拓展。 这股热潮也带动了另一个趋势——本地部署与算力硬件需求的快速增长。越来越多开发者尝试在个人设备或企业服务器上运行 Agent 系统,以获得更高的控制权和数据安全性。 从表面上看,AI Agent 似乎正从“概念验证”走向更广泛的开发实践。但在企业环境中,情况却没有想象中乐观。当企业负责人开始追问—— “它能直接解决我的业务问题吗?” 很多演示级产品仍难以给出令人满意的答案。 如何让 Agent 真正融入企业既有系统、适配复杂业务流程,正成为大模型产业落地必须跨越的一道门槛。 与此同时,中国不同城市的产业结构差异明显:互联网、

By Ne0inhk
二手平台出现OpenClaw卸载服务,299元可上门“帮卸”;2026年春招AI人才身价暴涨:平均月薪超6万;Meta辟谣亚历山大·王离职 | 极客头条

二手平台出现OpenClaw卸载服务,299元可上门“帮卸”;2026年春招AI人才身价暴涨:平均月薪超6万;Meta辟谣亚历山大·王离职 | 极客头条

「极客头条」—— 技术人员的新闻圈! ZEEKLOG 的读者朋友们好,「极客头条」来啦,快来看今天都有哪些值得我们技术人关注的重要新闻吧。(投稿或寻求报道:[email protected]) 整理 | 苏宓 出品 | ZEEKLOG(ID:ZEEKLOGnews) 一分钟速览新闻点! * 微信员工辟谣“小龙虾可自动发红包”:不要以讹传讹 * 蚂蚁集团启动春招,超 70% 为 AI 相关岗位 * 受贿 208 万!拼多多一员工被抓 * 2026 年春招 AI 人才身价暴涨: 平均月薪超 6 万元 * 二手平台出现 OpenClaw 上门卸载服务 * 权限太高,国家互联网应急中心发布 OpenClaw 安全应用的风险提示 * 字节豆包内测 AI 电商功能:无需跳转抖音,日活用户数超

By Ne0inhk
遭“美国政府封杀”后,Anthropic正式提起诉讼!

遭“美国政府封杀”后,Anthropic正式提起诉讼!

整理 | 苏宓 出品 | ZEEKLOG(ID:ZEEKLOGnews) 据路透社报道,当地时间周一,AI 初创公司 Anthropic 正式对美国国防部及特朗普政府提起诉讼,抗议五角大楼将其列为“国家安全供应链风险”主体的决定。 Anthropic 在向美国加州北区地方法院提交的诉讼文件中表示,这一认定“史无前例且非法”,已对公司造成“不可挽回的损害”。公司希望法院撤销该决定,并指示联邦机构停止执行相关认定。 划定 AI 应用红线,双方观点不一 正如我们此前报道,这场争端的核心在于 Anthropic 为其核心 AI 模型 Claude 设定的两条技术使用红线,与美国国防部的使用需求发生根本冲突。 此前,Anthropic 曾与五角大楼签署一份价值最高可达 2 亿美元的合作合同,Claude 也成为少数被纳入美国机密网络环境进行测试的 AI 系统之一。 对此,Anthropic 一直坚持两条底线: * Claude 等技术不得被用于对美国民众的大规模国内监控;

By Ne0inhk
为省5-10美元差点毁库!Claude一条指令删光200万条数据、网站停摆24小时,创始人坦言:全是我的错

为省5-10美元差点毁库!Claude一条指令删光200万条数据、网站停摆24小时,创始人坦言:全是我的错

编译 | 屠敏 出品 | ZEEKLOG(ID:ZEEKLOGnews) AI 时代,一次看似普通的操作,竟能让整套生产环境与近 200 万条数据瞬间「归零」。 近日,数据科学社区 DataTalks.Club 创始人 Alexey Grigorev 就遭遇了这样的惊魂时刻,他在使用 AI 编程工具 Claude Code 管理网站服务器时,意外清空了平台积累 2.5 年的核心数据,甚至连数据库快照也未能幸免,导致网站停摆整整 24 小时。 这起事故不仅在开发者社区引发热议,更给所有依赖 AI 工具与自动化运维的从业者敲响了警钟。事后,Alexey Grigorev 公开复盘了整个过程,并揭露了此次事故的核心问题。让我们一起看看。 一次看似很普通的网站迁移 这场“删库”事件的前因,其实并不复杂。

By Ne0inhk