刷题 DAY4

news2025/1/16 10:58:34

题目1

给定一个有序数组arr,给定一个正数aim

(1)返回累加和为aim的,所有不同二元组

(2)返回累加和为aim的,所有不同三元组

问题一

暴力的解法就是 遍历每一个二元组 找和为aim的

当然 只用暴力解很难ac 想一想有序 那肯定就是能加速 我们可以选择 先抓住一个数 然后另一个数用二分查找 确实把复杂度从O(N²)缩小到 O(N*logN)

解题的时候还想过用单调栈或者滑动窗口 不过这个答案又不一定是连续的 只能作罢

预处理累加数组 也不能加速查找

更好的做法是 双指针法 左右指针分别放在0位置和N-1位置 那么是有序的数组 所以可以让左指针右移让整体和增加 右指针左移 让整体和减少 复杂度为O(N)

捋一下做法

(1)当sum<aim 左指针右移

(2)sum>aim 右指针左移

(3)sum == aim 左指针右移和左指针右移都可以 本质上来讲就是换一种尝试

public static void selectTwo(int [] arr,int aim) {
		int left = 0;
		int right = arr.length-1;
		int sum = 0;
		while(left<=right-1) {
			sum = arr[left] + arr[right];
			if(sum<aim) {
				left++;
			}
			if(sum>aim) {
				right--;
			}
			if(sum==aim) {
				System.out.println(arr[left]+"  "+arr[right]);
				left++;
			}
		}
	}

问题二

简单 先以选定每一个数为 三元组中第一个数 然后转化为二元问题

	public static void selectTwo(int [] arr,int aim,int i,int index) {
		int left = i;
		int right = arr.length-1;
		int sum = 0;
		while(left<=right-1) {
			sum = arr[left] + arr[right];
			if(sum<aim) {
				left++;
			}
			if(sum>aim) {
				right--;
			}
			if(sum==aim) {
				System.out.println(index+" "+arr[left]+"  "+arr[right]);
				left++;
			}
		}
	}
	private static void selectThree(int [] arr,int aim) {
		for(int i = 0;i<=arr.length-1;i++) {
			selectTwo(arr, aim-arr[i],i,arr[i]);
		}
		

题目二

问题一

给定一个数组arr,已知其中所有的值都是非负的,将这个数组看作一个容器,请返回容器能装多少水比如,arr={3,1,2,5,2,4),根据值画出的直方图就是容器形状,该容器可以装下5格水再比如,arr={4,5,1,3,2},该容器可以装下2格水

遍历每一个位置可以装多少水 当前位置的装水数就是 左侧的最大值和右侧的最大值取最小值 再减去当前高度 然后如果是负数就不考虑(这是考虑了一种 当前位置一柱擎天的可能性 如果它比其他位置高的很多 也是放不了水的)最左侧和最右侧的格子上面肯定放不了水

用最大值数组 代替遍历行为

我刚开始确实想到用预处理数组了 但是咋想咋不对 你说那左侧右侧最大值 那不得分一个左侧最大值数组 再分一个右侧最大值数组 每个位置的最大值还不同 那不就是遍历了吗 后来看了答案想出来了 先来一个正序的最大值数组 那么当前位置的左侧最大高度就是当前的位置的值

再来一个逆序的数组

3 4 5 2 6 3 1 2 7 2 3 4

7 7 7 7 7 7 7 7 7 4 4 4 

右侧最大值就是当前位置

比如说5位置上的最大放水数

那就是6 7比较小的 也就是6 

public static int MaxWater(int [] arr) {
		int N = arr.length;
		int [] leftside = new int [N];
		int [] rightside = new int [N];
		leftside[0] = arr[0];
		rightside[N-1] =  arr[N-1];
		int sum = 0;
		for(int i = 1;i<N;i++) {
			leftside[i] = Math.max(arr[i],leftside[i-1]);
		}
		for(int i = N-2;i>=0;i--) {
			rightside[i] = Math.max(arr[i],rightside[i+1]);
		}
		for(int i = 1;i<N-1;i++) {
			int tmp = Math.min(leftside[i], rightside[i])-arr[i];
			if(tmp>0) {
				sum += tmp;
			}
		}
		return sum;
	}

这个方法需要两个临时数组的空间 且遍历三遍N大小的数组

吾有一言:一个算法要么对空间不友好 要么对时间不友好 要么对我的脑子不友好 三者至少取其二

所以下面还有一个优化解法

我们这次不需要临时数组 只需要双指针 左指针从1位置开始 右指针从N-2位置开始 再用leftmax记录当前左指针左侧目前最大值 再用rightmax记录当前右指针右侧最大值

对于左指针来说 如果它当前的左边的最大值(leftmax) 小于 右侧目前指针的最大值(rightmax) 右侧目前指针最大值为N 那么接下来的值 如果小于N 那么接下来的位置不会被更新为最大值 如果大于N 那更大于左边了 所以在这种情况 左边的值一定是最大值中的最小值

那如果leftmax > rightmax 是不是就啥都说明不了了呢 确实是这样的 但是我们可以反过来看 rightmax<leftmax了 这又可以执行上面的逻辑

当一个位置的水数判断完后 就把指针向下一个位置推动 判断下一个位置即可

public static int water2(int[] arr) {
		if (arr == null || arr.length < 2) {
			return 0;
		}
		int N = arr.length;
		int L = 1;
		int leftMax = arr[0];
		int R = N - 2;
		int rightMax = arr[N - 1];
		int water = 0;
		while (L <= R) {
			if (leftMax <= rightMax) {
				water += Math.max(0, leftMax - arr[L]);
				leftMax = Math.max(leftMax, arr[L++]);
			} else {
				water += Math.max(0, rightMax - arr[R]);
				rightMax = Math.max(rightMax, arr[R--]);
			}
		}
		return water;
	}

二维装水问题

就是给一个二维数组 其他和上一题一样

你或许会想把它拆成多个一维的 但是不完全是这样 假如拆成一列一列的话 还要受行上面的限制

那么暴力解法就是 把按行拆的结果放进二维数组中 再把按列拆的结果放进二维数组中 然后遍历两个数组 取每个位置上的更小值作为当前位置的结果 然后再累加 费老劲了

优化做法 说实话已经和一维的一点关系没有了

遍历它的外面一圈 把它放到小根堆中 然后弹出堆顶元素 然后把这个元素作为max 然后把它的上下左右四个位置加入到小根堆中  并结算当前位置水数(由于这个位置就是max 所以没有水) 然后以此类推 弹出堆顶 结算水数 然后把上下左右没加入过的位置加到小根堆中 直到弹出的值比当前max 大 那么就把max替换掉 接着刚才的操作 直到堆中没有任何元素

本质上很简单 先把最外面的一圈遍历了 找到第一个缺口(最小值) 如果没有任何缺口也无所谓 随便找一个地方开始行动 然后找到了这个点呢 就用感染算法看它的前后左右 如果比这个点低的话就说明这个地方有水 遍历这个坑 (因为最开始都是把最外面的一圈给加进小根堆 所以下一个弹出的 一定是刚才加入的较小值 如果大的话不会跑到小根堆顶 不要担心从另一边全部漏走的可能性 因为当前我们拿到的点就是最小值) 然后这个坑遍历完了呢 就会换max 换max就是换了个坑的意思

public static int MaxWater(int [][] arr) {
		if(arr==null||arr.length==0||arr[0].length==0) {
			return 0;
		}
		int N = arr.length;
		int M = arr[0].length;
	   boolean [][] has = new boolean [N][M];
	   PriorityQueue<Node> queue = new PriorityQueue<Node>(new mycompare());
	   for(int i = 0;i<M;i++) {
		   queue.add(new Node(0, i, arr[0][i]));
		   has[0][i] = true;
	   }
	   for(int i = 0;i<M;i++) {
		   queue.add(new Node(N-1, i, arr[N-1][i]));
		   has[0][i] = true;
	   }
	   for(int i = 1;i<N-1;i++) {
		   queue.add(new Node(i, 0, arr[i][M-1]));
		   has[i][M-1] = true;
	   }
	   for(int i = 1;i<N-1;i++) {
		   queue.add(new Node(i, M-1, arr[i][0]));
		   has[i][M-1] = true;
	   }
	   int max = Integer.MIN_VALUE;
	   int sum = 0;
	   while(!queue.isEmpty()) {
		   Node node = queue.poll();
		   int row = node.row;
		   int col = node.col;
		   int val = node.value;
		   max = Math.max(max,val);
		   
		   if(row-1>=0&&has[row-1][col]==false) {
			   queue.add(new Node(row-1,col,arr[row-1][col]));
			   has[row-1][col] = true;
               if(max-arr[row-1][col]>0) {
			   sum += max-arr[row-1][col];
		   }
		   }
		   if(col-1>=0&&has[row][col-1]==false) {
			   queue.add(new Node(row,col-1,arr[row][col-1]));
			   has[row][col-1] = true;
               if(max-arr[row][col-1]>0) {
			   sum += max-arr[row][col-1];
		   }
		   }
		   if(row+1<N&&has[row+1][col]==false) {
			   queue.add(new Node(row+1,col,arr[row+1][col]));
			   has[row+1][col]= true;
               if(max-arr[row+1][col]>0) {
			   sum += max-arr[row+1][col];
		   }
		   }
		   if(col+1<M&&has[row][col+1]==false) {
			   queue.add(new Node(row+1,col,arr[row][col+1]));
			   has[row][col+1] = true;
                if(max-arr[row][col+1]>0) {
			   sum += max-arrarr[row][col+1];
		   }
		   }		   
	   }
	   return sum;
	}

 刚开始加边界的时候 只加了右侧和上侧 忘记还有两边了

再有 每次应在加入节点时计算水 而不是弹出节点时计算水 我没想明白为啥 虽然没想明白弹出时有啥问题 但还是先这么写吧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/755634.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RocketMQ下载安装、集群搭建保姆级教程

目录 1.下载安装 2.配置 3.测试 4.集群配置 4.1.规划 4.2.环境准备 4.3.节点配置 4.3.1.master1 4.3.2.slave2 4.3.3.master2 4.3.4.slave1 4.4.启动 4.5.测试 1.下载安装 前置条件&#xff1a; JDK环境 下载地址&#xff1a; 下载 | RocketMQ 博主下载的是4.…

排序算法笔记--摩尔投票算法

摩尔投票算法 摩尔投票算法是一种用于在数组中查找出现次数超过一半的元素的有效算法。算法的核心思想是利用候选元素和计数器进行投票&#xff0c;通过消除不同元素之间的抵消来找到出现次数超过一半的元素。 算法原理 如果数组中存在一个出现次数超过一半的元素&#xff0…

【从零开始学习CSS | 第三篇】选择器优先级

目录 前言&#xff1a; 常见选择器的优先级&#xff08;从高到低&#xff09; 选择器的权重&#xff1a; 总结&#xff1a; 前言&#xff1a; 在前几篇文章中我们介绍了大量的选择器&#xff0c;那么大量的选择器在使用的时候&#xff0c;一定是有一个优先级顺序的&#xff…

graylog源码搭建

这里主要讲如何源码安装graylog 下载地址&#xff1a; https://www.graylog.org/downloads/ 下载带有JVM的源码文件源码安装 下载graylog-5.1.3-linux-x64.tgz&#xff0c;并上传到Centos中&#xff0c;执行以下操作 tar -zxvf graylog-5.1.3-linux-x64.tgzcd /etcmkdir -p …

Python GUI编程利器:Tkinker中的颜色选择对话框(15)

小朋友们好&#xff0c;大朋友们好&#xff01; 我是猫妹&#xff0c;一名爱上Python编程的小学生。 和猫妹学Python&#xff0c;一起趣味学编程。 今日目标 学习Tkinter中的颜色对话框的使用&#xff0c;实现如下效果&#xff1a; 颜色选择对话框 颜色选择对话框可以提供一…

JavaWeb 笔记——6

JavaWeb 笔记——6 一、Vue1.1、Vue-概述1.2、Vue快速入门1.3、Vue常用指令1.3、Vue生命周期1.4、查询所有-案例1.5、新增品牌-案例 二、Element2.1、Element概述2.2、快速入门2.3、Element布局2.4、常用组件 三、综合案例3.1、换件搭建3.2、查询所有3.3、新增品牌3.4、Servlet…

集群基础2——LVS负载均衡apache(nat模式)

文章目录 一、环境说明一、配置调度器网卡二、配置后端服务器三、配置调度器四、验证五、设置https负载均衡 一、环境说明 使用lvs中的nat模型&#xff0c;对apache负载均衡集群。 主机IP角色安装服务真实IP&#xff1a;192.168.161.129VIP&#xff1a;192.168.161.130调度服务…

证照之星软件怎么样?证照之星怎么换背景色

随着科技的快速发展&#xff0c;越来越多的软件应用于各个方面&#xff0c;为人们的生活和工作带来便利。今天&#xff0c;我们要介绍的就是一款证件照制作方面的软件——证照之星。那么&#xff0c;证照之星到底是什么软件&#xff1f;它好用吗&#xff1f;这篇文章将为大家详…

【PHP面试题45】cgi与fast_cgi关系是怎么样的

文章目录 一、CGI与FastCGI简介二、CGI与FastCGI的关系三、CGI与FastCGI的应用场景四、总结 一、CGI与FastCGI简介 本文已收录于PHP全栈系列专栏&#xff1a;PHP面试专区。 计划将全覆盖PHP开发领域所有的面试题&#xff0c;对标资深工程师/架构师序列&#xff0c;欢迎大家提前…

解析!1V1直播源码开发搭建技术实时语音识别翻译功能的应用

语言是我们人类交流的工具&#xff0c;它的种类繁多&#xff0c;比如世界语言&#xff0c;像是中国的汉语、英国的英语、法国的法语等&#xff1b;又或是我们中国的方言&#xff0c;像是山东话、北京话、上海话等。可谓是五花八门&#xff0c;争奇斗艳&#xff0c;每一种世界语…

MySQL的安装与卸载

1. MySQL安装 连接MySQL cmd或自带工具或Navicat 2. MSQL卸载

怎么管理酒店后勤维修工作?如何提高客户满意度?

酒店维修不及时会对客户满意度产生负面影响。当客人入住酒店时&#xff0c;如果发现设施设备出现故障或损坏&#xff0c;会直接影响客人的入住体验和满意度。如果这些故障或损坏得不到及时维修和解决&#xff0c;客人会对酒店的服务质量和信誉产生怀疑&#xff0c;可能会对酒店…

3.2.17 什么是数组及应用

【分享成果&#xff0c;随喜正能量】人这一生&#xff0c;好不好都得自己走&#xff0c;累不累都得自己承受。每个人都有难言之苦&#xff0c;每个人都有无声的泪&#xff0c;岁月可曾放过谁&#xff1f;再风光的人&#xff0c;背后都有寒凉凄楚&#xff0c;再幸福的人&#xf…

【UE4 塔防游戏系列】04-敌人沿着指定路线移动

目录 效果 步骤 一、绘制道路 二、创建出生点和路径点 三、生成敌人 四、敌人沿着路径点移动 效果 步骤 一、绘制道路 首先绘制一条道路&#xff0c;后面希望敌人会沿着这条绘制道路行走。 二、创建出生点和路径点 2.1 新建父类为Actor的蓝图&#xff0c;作为敌人出…

Docker——认识Docker 常用命令 Linux中安装docker 常见问题及其解决

目录 引出Docker是啥&#xff1f;Docker是啥&#xff1f;Docker VS 虚拟机1.特性优势2.资源优势 Docker的架构Docker常用命令&#xff08;1&#xff09;docker ps&#xff08;2&#xff09;docker stop 容器名称&#xff08;3&#xff09;docker ps -a&#xff08;4&#xff0…

css基础知识二十:说说对Css预编语言的理解?有哪些区别?

一、是什么 Css 作为一门标记性语言&#xff0c;语法相对简单&#xff0c;对使用者的要求较低&#xff0c;但同时也带来一些问题 需要书写大量看似没有逻辑的代码&#xff0c;不方便维护及扩展&#xff0c;不利于复用&#xff0c;尤其对于非前端开发工程师来讲&#xff0c;往…

[java安全]CommonsCollections3.1

文章目录 【java安全】CommonsCollections3.1InvokerTransformerConstantTransformerChainedTransformerTransformedMap如何触发checkSetValue()方法&#xff1f;AnnotationInvocationHandlerpoc利用链 【java安全】CommonsCollections3.1 java开发过程中经常会用到一些库。Ap…

【Python 基础篇】Python环境搭建

文章目录 一、Python环境的下载二、Python环境变量的安装及配置三、Python编译器的选择一、Python环境的下载 Python官方网站:www.python.org 这个是Python的官方网站,Python下载以及相关文档都能在里面找到 如果下载慢的话,可以在各大电脑应用市场下载(自己是在联想应用商…

【分布式任务调度】XXL-JOB调度中心集群部署配置(一)

文章目录 1.概述2.代码编译2.1.代码下载2.2.初始化与编译 3.集群部署3.1.服务启动3.2.反向代理 4.结语 1.概述 XXL-JOB是一款轻量级的分布式任务调度中间件&#xff0c;默认支持6000个定时任务&#xff0c;如果生产环境的任务数量在这个范围内&#xff0c;可以选择使用 XXL-JO…