2023-09-05:请用go语言编写。一个图像有n个像素点,存储在一个长度为n的数组arr里, 每个像素点的取值范围[0,s]的整数, 请你给图像每个像素点值加上一个整数k(可以是负数), 像素值会
2023-09-05:请用go语言编写。一个图像有n个像素点,存储在一个长度为n的数组arr里,
每个像素点的取值范围[0,s]的整数,
请你给图像每个像素点值加上一个整数k(可以是负数),
像素值会自动截取到[0,s]范围,
当像素值<0,会更改为0,当新像素值>s,会更改为s,
这样就可以得到新的arr,想让所有像素点的平均值最接近中位值s/2, 向下取整。
请输出这个整数k, 如有多个整数k都满足, 输出小的那个。
1 <= n <= 10^6,
1 <= s <= 10^18。
来自华为OD。
来自左程云。
答案2023-09-05:
根据代码和题目描述,可以将算法分为以下三种不同的方法:
方法一:暴力方法
这种方法通过枚举k的值来计算每个像素值加上k后的平均值,然后选择平均值最接近中位值s/2的k。
该方法采用两层循环:外层循环枚举k的取值,内层循环计算平均值。
时间复杂度:O(n^2)
空间复杂度:O(1)
方法二:优化暴力方法
这种方法在暴力方法的基础上进行了一些优化,采用二分查找来减少计算的次数。
首先,确定k的取值范围为[-s, s],然后进行二分查找来逼近平均值最接近中位值s/2的k。
时间复杂度:O(n*log(s))
空间复杂度:O(1)
方法三:正式方法(最优解)
这种方法是一种最优解,通过先对数组arr进行排序,然后使用前缀和数组pre来存储累加和,以便在计算过程中快速计算区间和。
确定k的取值范围,根据k的正负分别进行二分查找,得到最接近中位值s/2的k。
时间复杂度:O(nlog(n) + log(s)log(n))
空间复杂度:O(n)
go完整代码如下:
package main
import (
"fmt"
"math"
"math/rand"
"sort"
)
// 暴力方法
// 为了测试
func best1(arr []int, s int) int {
half := s / 2
average := -100000
ans := -s
for k := -s; k <= s; k++ {
curAverage := average1(arr, k, s)
if math.Abs(float64(half-curAverage)) < math.Abs(float64(half-average)) {
average = curAverage
ans = k
}
}
return ans
}
// 暴力方法
// 为了测试
func average1(arr []int, k, s int) int {
sum := 0
for _, num := range arr {
value := num + k
if value < 0 {
sum += 0
} else if value > s {
sum += s
} else {
sum += value
}
}
return sum / len(arr)
}
// 优化了一下,但不是最优解
func best2(arr []int, s int) int {
l := -s
r := s
m := 0
half := s / 2
average := -s
ans := 0
for l <= r {
m = (l + r) / 2
curAverage := average1(arr, m, s)
if math.Abs(float64(half-curAverage)) < math.Abs(float64(half-average)) ||
(math.Abs(float64(half-curAverage)) == math.Abs(float64(half-average)) && m < ans) {
average = curAverage
ans = m
}
if curAverage >= half {
r = m - 1
} else {
l = m + 1
}
}
return ans
}
// 正式方法
// 最优解
// O(N * logN) + O(logS * logN)
func best3(arr []int, s int) int {
sort.Ints(arr)
sum := make([]int, len(arr))
sum[0] = arr[0]
for i := 1; i < len(arr); i++ {
sum[i] = sum[i-1] + arr[i]
}
l := -s
r := s
m := 0
half := s / 2
average := -s
ans := 0
for l <= r {
m = (l + r) / 2
curAverage := average3(arr, sum, m, s)
if math.Abs(float64(half-curAverage)) < math.Abs(float64(half-average)) ||
(math.Abs(float64(half-curAverage)) == math.Abs(float64(half-average)) && m < ans) {
average = curAverage
ans = m
}
if curAverage >= half {
r = m - 1
} else {
l = m + 1
}
}
return ans
}
func average3(arr []int, pre []int, k, s int) int {
n := len(arr)
if k < 0 {
l := bsZero(arr, k)
sum := rangeSum(pre, l+1, n-1)
return (sum + (k * (n - l - 1))) / n
} else {
r := bsS(arr, k, s)
sum := rangeSum(pre, 0, r-1)
return (sum + (k * r) + (s * (n - r))) / n
}
}
func bsZero(arr []int, k int) int {
ans := -1
l := 0
r := len(arr) - 1
var m int
for l <= r {
m = (l + r) / 2
if arr[m]+k <= 0 {
ans = m
l = m + 1
} else {
r = m - 1
}
}
return ans
}
func bsS(arr []int, k, s int) int {
ans := len(arr)
l := 0
r := len(arr) - 1
var m int
for l <= r {
m = (l + r) / 2
if arr[m]+k >= s {
ans = m
r = m - 1
} else {
l = m + 1
}
}
return ans
}
func rangeSum(pre []int, l, r int) int {
if l > r {
return 0
}
if l == 0 {
return pre[r]
}
return pre[r] - pre[l-1]
}
// 为了测试
func randomArray(n, s int) []int {
arr := make([]int, n)
for i := 0; i < n; i++ {
arr[i] = randInt(0, s)
}
return arr
}
func randInt(min, max int) int {
return min + rand.Intn(max-min+1)
}
func main() {
N := 50
S := 500
testTimes := 10000
fmt.Println("测试开始")
for i := 0; i < testTimes; i++ {
n := randInt(1, N)
s := randInt(1, S)
arr := randomArray(n, s)
ans1 := best1(arr, s)
ans2 := best2(arr, s)
ans3 := best3(arr, s)
if ans1 != ans2 || ans1 != ans3 {
fmt.Println("出错了!")
}
}
fmt.Println("测试结束")
}

c++完整代码如下:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int average1(vector<int>& arr, int k, int s);
int average3(vector<int>& arr, vector<int>& pre, int k, int s);
int bsZero(vector<int>& arr, int k);
int bsS(vector<int>& arr, int k, int s);
int rangeSum(vector<int>& pre, int l, int r);
int best1(vector<int>& arr, int s);
int best2(vector<int>& arr, int s);
int best3(vector<int>& arr, int s);
vector<int> randomArray(int n, int s);
void test();
int average1(vector<int>& arr, int k, int s) {
int sum = 0;
for (int num : arr) {
int value = num + k;
if (value < 0) {
sum += 0;
}
else if (value > s) {
sum += s;
}
else {
sum += value;
}
}
return sum / arr.size();
}
int average3(vector<int>& arr, vector<int>& pre, int k, int s) {
int n = arr.size();
if (k < 0) {
int l = bsZero(arr, k);
int sum = rangeSum(pre, l + 1, n - 1);
return (sum + (k * (n - l - 1))) / n;
}
else {
int r = bsS(arr, k, s);
int sum = rangeSum(pre, 0, r - 1);
return (sum + (k * r) + (s * (n - r))) / n;
}
}
int bsZero(vector<int>& arr, int k) {
int ans = -1;
int l = 0;
int r = arr.size() - 1;
int m;
while (l <= r) {
m = (l + r) / 2;
if (arr[m] + k <= 0) {
ans = m;
l = m + 1;
}
else {
r = m - 1;
}
}
return ans;
}
int bsS(vector<int>& arr, int k, int s) {
int ans = arr.size();
int l = 0;
int r = arr.size() - 1;
int m;
while (l <= r) {
m = (l + r) / 2;
if (arr[m] + k >= s) {
ans = m;
r = m - 1;
}
else {
l = m + 1;
}
}
return ans;
}
int rangeSum(vector<int>& pre, int l, int r) {
if (l > r) {
return 0;
}
return l == 0 ? pre[r] : (pre[r] - pre[l - 1]);
}
int best1(vector<int>& arr, int s) {
int half = s / 2;
int average = -100000;
int ans = -s;
for (int k = -s; k <= s; k++) {
int curAverage = average1(arr, k, s);
if (abs(half - curAverage) < abs(half - average)) {
average = curAverage;
ans = k;
}
}
return ans;
}
int best2(vector<int>& arr, int s) {
int l = -s;
int r = s;
int m = 0;
int half = s / 2;
int average = -s;
int ans = 0;
while (l <= r) {
m = (l + r) / 2;
int curAverage = average1(arr, m, s);
if ((abs(half - curAverage) < abs(half - average))
|| ((abs(half - curAverage) == abs(half - average)) && m < ans)) {
average = curAverage;
ans = m;
}
if (curAverage >= half) {
r = m - 1;
}
else {
l = m + 1;
}
}
return ans;
}
int best3(vector<int>& arr, int s) {
sort(arr.begin(), arr.end());
vector<int> sum(arr.size());
sum[0] = arr[0];
for (int i = 1; i < arr.size(); i++) {
sum[i] = sum[i - 1] + arr[i];
}
int l = -s;
int r = s;
int m = 0;
int half = s / 2;
int average = -s;
int ans = 0;
while (l <= r) {
m = (l + r) / 2;
int curAverage = average3(arr, sum, m, s);
if ((abs(half - curAverage) < abs(half - average))
|| ((abs(half - curAverage) == abs(half - average)) && m < ans)) {
average = curAverage;
ans = m;
}
if (curAverage >= half) {
r = m - 1;
}
else {
l = m + 1;
}
}
return ans;
}
vector<int> randomArray(int n, int s) {
vector<int> arr(n);
for (int i = 0; i < n; i++) {
arr[i] = rand() % (s + 1);
}
return arr;
}
void test() {
int N = 50;
int S = 500;
int testTimes = 10000;
cout << "测试开始" << endl;
for (int i = 0; i < testTimes; i++) {
int n = rand() % N + 1;
int s = rand() % S + 1;
vector<int> arr = randomArray(n, s);
int ans1 = best1(arr, s);
int ans2 = best2(arr, s);
int ans3 = best3(arr, s);
if (ans1 != ans2 || ans1 != ans3) {
cout << "出错了!" << endl;
}
}
cout << "测试结束" << endl;
}
int main() {
test();
return 0;
}

2023-09-05:请用go语言编写。一个图像有n个像素点,存储在一个长度为n的数组arr里, 每个像素点的取值范围[0,s]的整数, 请你给图像每个像素点值加上一个整数k(可以是负数), 像素值会的更多相关文章
- 面试题:给定一个长度为N的数组,其中每个元素的取值范围都是1到N。判断数组中是否有重复的数字
题目:给定一个长度为N的数组,其中每个元素的取值范围都是1到N.判断数组中是否有重复的数字.(原数组不必保留) 方法1.对数组进行排序(快速,堆),然后比较相邻的元素是否相同.时间复杂度为O(nlog ...
- 在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3
// test14.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include< ...
- opencv入门系列教学(五)图像的基本操作(像素值、属性、ROI和边框)
0.序言 每个图像是由一个个点组成的,而这些点可以表示为像素值的形式. 这篇博客里我们将学会: 访问像素值并修改它们 . 访问图像属性 . 设置感兴趣区域(ROI) . 分割和合并图像. 对于图像的基 ...
- 问题-MyBatis不识别Integer值为0的数据
问题-MyBatis不识别Integer值为0的数据 问题:使用MyBatis的过程中,发现一个值为0的数据,Mybatis所识别,最后定位才发现,是自己的写法有问题, <if test=&qu ...
- AE IRasterCursor 改变栅格图层像素值
1 public void ChangePixelValue(double xMax, double xMin, double yMax, double yMin,double[,] PixelCha ...
- C/C++编程笔记:C语言入门知识点(三),请收藏C语言最全笔记!
今天我们继续来学习C语言的入门知识点,第一课:C/C++编程笔记:C语言入门知识点(二),请收藏C语言最全笔记! 21. 输入 & 输出 当我们提到输入时,这意味着要向程序填充一些数据.输入可 ...
- C/C++编程笔记:C语言入门知识点(二),请收藏C语言最全笔记!
今天我们继续来学习C语言的入门知识点 11. 作用域规则 任何一种编程中,作用域是程序中定义的变量所存在的区域,超过该区域变量就不能被访问.C 语言中有三个地方可以声明变量: 在函数或块内部的局部变量 ...
- 请为CMyString类型编写构造函数、copy构造函数、析构函数和赋值运算符函数。
如下为类型CMyString的声明,请为该类型编写构造函数.copy构造函数.析构函数和赋值运算符函数. class CMyString { public: CMyString(const char* ...
- C/C++编程笔记:C语言入门知识点(一),请收藏C语言最全笔记!
C语言简介 C 语言是一种通用的高级语言,最初是由丹尼斯·里奇在贝尔实验室为开发 UNIX 操作系统而设计的.C 语言最开始是于 1972 年在 DEC PDP-11 计算机上被首次实现. 原文链接: ...
- (面试题)请用C语言实现在32位环境下,两个无符号长整数相加的函数,相加之和不能存储在64位变量中
分析:长整数相加,将结果分为高位和低位部分,分别保存在两个32整数中. 比如:unsigned int a = 0xFFFFFFFF, unsigned int b = 0x1, 结果用unsigne ...
随机推荐
- SpringSecurity-前后端分离教程
1.简介 Spring Security 是 Spring 家族中的一个安全管理框架.相比与另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富. 一般来说中大型的项目都是使用 ...
- Mac 下使用 ffmpeg 制作 gif
Mac 下使用 ffmpeg 制作 gif 公众号文章,gif要求 300帧数以内 .以下是从 mp4 转为 gif 的步骤. 步骤 ffmpeg 是著名的视频处理开源软件 brew ...
- python~windows自动化工具 uiautomation库
微软提供了关于自动化操作PC端桌面应用程序的工具,官方描述为: Microsoft UI Automation is an accessibility framework that enables W ...
- VS Code C# 开发工具包正式发布
前言 微软于本月正式发布Visual Studio Code C#开发工具包,此前该开发套件已经以预览版的形式在6月份问世.经过4个月的测试和调整,微软修复了350多个问题,其中大部分是用户反馈导致的 ...
- select...for update到底是加了行锁,还是表锁?
前言 前几天,知识星球中的一个小伙伴,问了我一个问题:在MySQL中,事务A中使用select...for update where id=1锁住了,某一条数据,事务还没提交,此时,事务B中去用sel ...
- Linux 回收站
聊一聊执行 rm -rf 数据恢复以及建立 Linux 回收站 误删除 rm -rf 如果在Linux 平台下,执行 rm -rf 误删除文件,我们可以做哪些数据恢复的工作以及我们该如何应对不小心删除 ...
- 采药(lgP1048)
emmm 01 背包模板... 设 f[i] 表示背包容积为 i 时所得的最大价值. 则状态转移方程为 f[j] = f[j - w[i]] + c[i] . #include<bits/std ...
- 线性dp数字三角形
数字三角形是最裸的题目,没有加入任何的背景,这里就不写了. 下面这道摘花生的题目就是数字三角形的应用 Hello Kitty想摘点花生送给她喜欢的米老鼠. 她来到一片有网格状道路的矩形花生地(如下图) ...
- 开发现代化的.NetCore控制台程序:(2)创建一个C#项目模板
前言 上一篇文章(开发一个现代化的.NetCore控制台程序,包含依赖注入/配置/日志等要素)介绍了开发现代化的.NetCore控制台程序的细节,但这还不够,我又创建了一个脚手架模板,并命名为 Flu ...
- 微服务系列-Spring Boot使用Open Feign 微服务通信示例
公众号「架构成长指南」,专注于生产实践.云原生.分布式系统.大数据技术分享. 前言 在前几个教程中我们已经看到: 使用 RestTemplate 的 Spring Boot 微服务通信示例 使用 We ...