找出[1,n]范围内按照字典排序的最小第k个值
1 题目描述
给定一个数组序列, 需要求选出一个区间, 使得该区间是所有区间中经过如下计算的值最大的一个:
区间中的最小数 * 区间所有数的和最后程序输出经过计算后的最大值即可,不需要输出具体的区间。如给定序列 [6 2 1]则根据上述公式, 可得到所有可以选定各个区间的计算值:
2 代码
最后一种代码好理解
import java.util.Scanner;
public class Main {
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
int size = sc.nextInt();
int [] input =new int [size];
for(int i=0;i<input.length;i++){
input[i] = sc.nextInt();
}
long max=input[0]*input[0];
for(int i=0;i<size;i++){
long sum=input[i];
int min=input[i];
for(int j=i+1;j<size;j++){
if(input[j]==0){
break;
}
sum+=input[j];
if(input[j]<min){
min = input[j];
}
if(min*sum>max){
max=min*sum;
}
}
}
System.out.println(max);
}
}
单调栈
def find_max(nums)
length = nums.size
# 预处理,先将累计和保存;若在出栈时再计算区间和,超时AC 80%
pre_sum = [nums[0]]
1.upto(nums.size - 1).each do |i|
pre_sum[i] = pre_sum[i-1] + nums[i]
end
# 先将第一个数字下标压入栈
index_satck = [0]
max_multi = 0
cur_index = 1
# 数组遍历结束但是栈不为空时仍要继续
while cur_index < length || (cur_index == n && index_satck.size > 0) do
# 当栈为空或者当前数大于等于栈顶元素,下标入栈
if cur_index < length && (index_satck.empty? || nums[cur_index] >= nums[index_stack[-1]])
index_satck << cur_index
cur_index += 1
# 当数组遍历结束或者当前数小于栈顶元素时
else
# 区间最小值为栈顶元素,出栈
min_num = nums[index_stack.pop]
# 如果此时栈为空了,表示已出栈的数字比前面所有数字都小,左边界下标也就是0,否则左边界下标为(下一个元素的索引+1)
cur_sum = pre_sum[cur_index - 1] - (index_stack.empty? ? pre_sum[index_stack[-1]] : 0)
cur_max = min_num * cur_sum
max_multi = max_multi > cur_max ? max_multi : cur_max
end
end
max_multi
end
size = gets.to_i
input = []
0.upto(size - 1).each do |index|
input << gets.to_i
end
max = input[0] ** 2
0.upto(size - 1).each do |index|
sum = input[index]
min = input[index]
(index + 1).upto(size - 1).each do |next_index|
break if input[next_index] == 0
sum += input[next_index]
if input[next_index] < min
min = input[next_index]
end
if min * sum > max
max = min * sum
end
end
end
p max
1、P为给定的二维平面整数点集。定义 P 中某点x,如果x满足 P 中任意点都不在 x 的右上方区域内(横纵坐标都大于x),则称其为“最大的”。求出所有“最大的”点的集合。(所有点的横坐标和纵坐标都不重复, 坐标轴范围在[0, 1e9) 内)
如下图:实心点为满足条件的点的集合。请实现代码找到集合 P 中的所有 ”最大“ 点的集合并输出。
2.变治法(预排序)
由“最大点”的性质可知,对于每一个“最大点”,若存在其他点的y值大于该点y值,那么其他点x值必然小于该点的x值。
换言之,当某一点确定它的x值高于所有y值大于它的点的x值,那么该点就是“最大点” 。网上给出的答案基本上都是这个套路。
对于y有序的点集,只需要O(n)即可输出“最大点”点集。一般基于比较的排序算法时间复杂度O(nlogn)。那么,显而易见,算法整体复杂度为O(nlogn)。
3.减治法+变治法(过滤+预排序)
先预处理一下
过滤很简单,就是在集合中找出一个比较好的点,然后过滤掉其左下角的所有点。然后再采用方法2对过滤后的点集求解。
那么这个集合中比较好的点,怎么找,或者说哪个点是比较好的点。显而易见,越靠近点集右上角的点,左下角的面积就越大,越可以过滤更多的点,故越好。
儿时学过,两个数的和一定,那么两数差越小,乘积越大。简单设计,该点x和y的和减去x和y差的绝对值越大,该点越好。
count = gets
# 1.字符串要转数字,否则index < count 会报数据类型错误
count = count.to_i
point_list = []
index = 0
while index < count do
x = gets
y = gets
point_list << {x: x.to_i, y: y.to_i}
index += 1
end
# 2、按照x坐标排序, 用的还是sort_by而不是sort
sorted_point_list = point_list.sort_by{|point| point[:x]}
# 不太可行,因为删除一个数据之后index,cur_index会永远小于count,所以count也要做减法
# 逐个比较y坐标
index = 0
while index < count do
# 因为在一直删除,所以要加判断
break if sorted_point_list[index].nil?
cur_point_y = sorted_point_list[index][:y]
point = sorted_point_list.find {|point| point[:y] > cur_point_y}
if point.nil?
index += 1
else
sorted_point_list.delete_at(index)
count -= 1
end
<!-- next_index = index + 1 -->
<!-- while next_index < count do -->
<!-- # 4、也要加非空判断 -->
<!-- break if sorted_point_list[next_index].nil? -->
<!-- next_point_y = sorted_point_list[next_index][:y] -->
<!-- if next_point_y > cur_point_y -->
<!-- break -->
<!-- end -->
<!-- next_index += 1 -->
<!-- end -->
<!-- -->
<!-- # 3、说明存在x,y均大于改点的坐标,这时下标不应该增加 -->
<!-- if next_index < count -->
<!-- sorted_point_list.delete_at(index) -->
<!-- count -= 1 -->
<!-- else -->
<!-- index += 1 -->
<!-- end -->
end
# 输出sorted_point_list
p "" if sorted_point_list.empty?
sorted_point_list.each do |point|
print point[:x] + " " + point[:y]
p ""
end
Show Disqus Comments