同时找到最大值和最小值——编程之美

同时找到最大值和最小值——编程之美

给定一个数组,我们可以同时找到其中的最大数和最小数吗?要求时间复杂度尽可能的小。

编程之美上面提供了三个思路,我把它们都实现了,并做一些讲解补充。

    思路一:

两次遍历,分别得到最大值和最小值。时间复杂度为O(2*N)。

    思路二:

把最前面的两个数作为最值的候选,然后后面的数两两一组,分别让其中的较大值和候选最值比较,让其中的较小值和候选最值比较。

感觉这种方法和推排序有点儿类似。。

    思路三:

采用分治法思想,把整个数组一分为二,让左边的最值和右边的最值分别比较,这里有个递归的过程,主要跳出递归的条件是当数组的begin和end相差小于等于1的时候,跳出。

上面三个思路的代码如下:

#include<iostream>
using namespace std; 

struct Pair
{
	int max, min;
};

// 遍历两次,时间复杂度为O(2*N)
Pair minMax_1(int a[], int n)
{
	int max = a[0], min = a[0]; 

	for(int i = 0; i < n; i++)
	{
		min = a[i] < min ? a[i]:min;
		max = a[i] > max ? a[i]:max;
	}

	Pair p;
	p.max = max;
	p.min = min; 

	return p;
}

// 两两比较,时间复杂度是O(1.5*N)
Pair minMax_2(int a[], int n)
{
	int max = a[0], min = a[1];
	if(max < min)
		swap(max, min); 

	for(int i = 2; i < n; i = i + 2)  // 递进2个
	{
		int tmpMin = a[i];
		int tmpMax = a[i+1];
		if(tmpMax < tmpMin)
			swap(tmpMin, tmpMax);   // 候选

		max = max > tmpMax ? max:tmpMax;
		min = min < tmpMin ? min:tmpMin;
	}

	// 防止长度为奇数
	max = max > a[n-1] ? max:a[n-1];
	min = min < a[n-1] ? min:a[n-1]; 	

	Pair p;
	p.max = max;
	p.min = min; 

	return p;
}

// 分治法,时间复杂度也是O(1.5*N)
Pair minMax_3(int a[], int begin, int end)
{
	Pair P;
	if(end - begin <= 1)
	{
		P.max = a[begin] > a[end] ? a[begin]:a[end];
		P.min = a[begin] < a[end] ? a[begin]:a[end];
		return P;
	}

	Pair PL = minMax_3(a, begin, begin + (end - begin) / 2);
	Pair PR = minMax_3(a, begin + (end - begin) / 2 + 1, end);
	P.max = PL.max > PR.max ? PL.max:PR.max;
	P.min = PL.min < PR.min ? PL.min:PR.min; 

	return P;
}

int main()
{
	Pair P;
	int a[] = {3, 6, 1, 8, 0};
	int n = 5; 

	// solution 1
	P = minMax_1(a, n);
	cout<<P.min<<' '<<P.max<<endl; 

	//solution 2
	P = minMax_2(a, n);
	cout<<P.min<<' '<<P.max<<endl; 

	//solution 3
	P = minMax_3(a, 0, n-1);
	cout<<P.min<<' '<<P.max<<endl; 

	return 0;
}
时间: 2024-08-19 12:33:06

同时找到最大值和最小值——编程之美的相关文章

编程之美2.14 求数组的子数组之和的最大值

问题描述: 一个有N个整数元素的一维数组(A[0], A[1], A[2],...,A[n-1]),这个数组当然有很多子数组,那么子数组之和的最大值是什么呢? 解法: 1. 暴力解法-------O(N^3) 2. 改进版暴力解法-------O(N^2) *3. 分治算法-------O(NlogN)(暂时未去实现) 4. 数组间关系法-------O(N) 具体思路和代码: 1.暴力解法 思路:Sum[i,...,j]为数组第i个元素到第j个元素的和,遍历所有可能的Sum[i,...,j].

编程之美2.3: 寻找发帖水王

题目:传说,Tango有一大"水王",他不但喜欢发帖,还会回复其他ID发的帖子,发帖数目超过帖子总数的一半,如果你有一个当前论坛上所有帖子的列表,其中帖子作者的ID也在表中,你能快速找到这个传说中的Tango水王吗? 解题思路:由于水王的发帖数目超过一半,当每次删除两个不同ID的帖子时,水王占得帖子数目仍然大于剩下帖子的一半,重复整个过程,将ID列表中的ID总数降低,转化为更小的问题,从而得到最后水王的ID. #include <iostream> #include <

编程之美2.17 数组循环移位

问题描述: 设计一个算法,把一个含有N元素的数组循环左移或者右移K位. 解决方法: 1. 暴力解法------O(KN) 2. 颠倒位置------O(N) 具体思路和代码: 1. 暴力解法------O(KN) 思路:循环K次,每次移动一位 代码: 1 //右移 2 void s1(int A[], int n, int k) 3 { 4 k = k % n; 5 for(int i = 0; i < k; i++) 6 { 7 int t = A[n-1]; 8 for(int j = n-

编程之美leetcode之编辑距离

Edit Distance Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.) You have the following 3 operations permitted on a word: a) Insert a character b) Delete a char

编程之美2.17之数组循环移位

题目描述:设计一个算法,把一个含有N个元素的数组循环右移K位,要求算法的时间复杂度位O(Log2N),且只允许使用两个附加变量. 什么意思呢,就是说如果输入序列为:abcd1234,右移2位即变为34abcd12.唯一的要求就是使用两个附加变量. 其实这道题编程珠玑上面也出现过,书中给出的一种符合题意的解法是巧妙地进行翻转.以把abcd1234右移4位为例: 第一步:翻转1234,abcd1234---->abcd4321 第二步:翻转abcd,abcd4321---->dcba4321 第三

编程之美2.13 子数组最大乘积

问题描述: 给定一个长度为N的整数数组,只允许用乘法,不能用除法,计算任意(N-1)个数的组合乘积中最大的一组,并写出算法的时间复杂度. 解法: 1.暴力解法------O(n^2) 2.前后缀法------O(n) 3.统计法--------O(n) 具体思路和代码: 1.暴力解法: 思路:利用两层循环,依次删掉一个,其余的做乘法,计算出最大的. 代码: 1 int s1(int A[], int n) 2 { 3 int s = 1; 4 int max; 5 for(int i = 1;

编程之美2.1 求二进制中1的个数

最近一段的时间,一直在看编程之美之类的算法书籍,刚开始看编程之美,感觉到难度太大,有时候也不愿意去翻动这本书,不过,经过一段时间的修炼,我也彻底的喜欢上这本书了, 书中的算法涉及到很多方面,树,链表,位运算,数组,hash表应用等等. 由于最近事情也忙得差不多了,我重新写了一遍编程之美中的算法,在这里记录下来,以便以后阅读方便. 第一道题从2.1写起,这道题目难度不是很大,首先,给出这个题目的函数声明: /*2.1 求二进制中1的个数*/ int DutCountOf1InBin_1(unsig

Java 编程之美:并发极速赛车平台出租编程高级篇

借用 Java 并发极速赛车平台出租haozbbs.comQ1446595067 编程实践中的话:编写正确的程序并不容易,而编写正常的并发程序就更难了. 相比于顺序执行的情况,多线程的线程安全问题是微妙而且出乎意料的,因为在没有进行适当同步的情况下多线程中各个操作的顺序是不可预期的. 并发编程相比 Java 中其他知识点学习起来门槛相对较高,学习起来比较费劲,从而导致很多人望而却步: 而无论是职场面试和高并发高流量的系统的实现却都还离不开并发编程,从而导致能够真正掌握并发编程的人才成为市场比较迫

编程之美2.10 寻找数组中的最大值和最小值

这个问题其实很容易解决,就是循环遍历一遍数组,然后找到数组中存在的最大值和最小值就可以了,书中主要讨论的问题是比较次数较小的方法,不过,书中已经证明了,无论用什么方法最少的比较次数也就是循环遍历一遍的比较,结果是O(1.5N)的,所以,很容易的可以解决这个问题. 第一种方法: 函数声明: void DutFindMaxAndMinInArray_1(int*, int, int&, int&); 源代码如下: /*基本的解法寻找最大值和最小值*/ bool _DutFindMaxAndMi