剑指offer第五章

时间:2022-09-07 00:00:46

剑指offer第五章

1.数组中出现次数超过一半的数

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
分析:
思路1:数组排序,排序之后中间的数字一定是出现次数超过数组长度一半的数字,也就是统计学上的中位数,即长度为n的数组中第n/2大的数字(数组中任意第k大的数字)
 class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers)
{
int length=numbers.size();
int ans=;
if(numbers.empty())
return ;
sort(numbers.begin(),numbers.end());//排序
int midNum=numbers[length/]; int count=;//统计次数初始化
for(int i=;i<length;i++)
{
if(numbers[i]==midNum)
++count;//次数统计
}
if(count>length/)//进行判断,是否为要求
ans=midNum;
return ans;
}
};
思路二:如果有符合条件的数字,则它出现的次数比其他所有数字出现的次数和还要多。 
在遍历数组时保存两个值:一是数组中一个数字,一是次数。遍历下一个数字时,若它与之前保存的数字相同,则次数加1,否则次数减1;若次数为0,则保存下一个数字,并将次数置为1。遍历结束后,所保存的数字即为所求。然后再判断它是否符合条件即可。
 class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers)
{
if(numbers.empty()) return ; // 遍历每个元素,并记录次数;若与前一个元素相同,则次数加1,否则次数减1
int result = numbers[];
int times = ; // 次数 for(int i=;i<numbers.size();++i)
{
if(times == )
{
// 更新result的值为当前元素,并置次数为1
result = numbers[i];
times = ;
}
else if(numbers[i] == result)
{
++times; // 相同则加1
}
else
{
--times; // 不同则减1
}
} // 判断result是否符合条件,即出现次数大于数组长度的一半
times = ;
for(int i=;i<numbers.size();++i)
{
if(numbers[i] == result) ++times;
} return (times > numbers.size()/) ? result : ;
}

2.最小的k个数

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
分析:最简单的思路:把输入的n个整数排序,取最前面的k个数,时间复杂度O(nlogn)
 class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k)
{
int length=input.size();
vector<int> ans;
if(input.empty()||k>length)
return ans;
sort(input.begin(),input.end());
for(int i=;i<k;i++)
ans.push_back(input[i]);
return ans;
}
};

3.连续子数组的最大和

HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。你会不会被他忽悠住?(子向量的长度至少是1)
分析:最直观的方法,即枚举出数组的所有子数组并求出他们的和。一个长度为n的数组,总共有n(n+1)/2个子数组,最快也需要O(n^2),时间复杂度比较高
代码采用下图所示方法:
剑指offer第五章
 class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array)
{
if (array.empty())
return ;
int temp1 = array[], max = array[];
for (int i = ; i < array.size(); i++)
{
if (temp1 + array[i] > array[i])
temp1 += array[i];
else
temp1 = array[i];
if (temp1 > max)
max = temp1;
}
return max; }
};

4.从1到n整数1出现的次数

求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。
希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。
分析:最直观的方法,就是累加1到n中每个整数1出现的次数。可以每次通过对10求余数判断整数的各位数字是不是1.如果这个数字大于10,除以10之后再判断各位数字是不是1
 class Solution {
public:
int numberOf1(int n)
{
int number=;
while(n)
{
if(n%==)
{
number++;
}
n=n/;
}
return number;
}
int NumberOf1Between1AndN_Solution(int n)
{
int number=;//参数初始化
for(int i=;i<=n;++i)
number+=numberOf1(i);
return number;
}
};

5.把数组排成最小的数

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
分析:先将整型数组转换成String数组,然后将String数组排序,最后将排好序的字符串数组拼接出来。关键就是制定排序规则。
对vector容器内的数据进行排序,按照 将a和b转为string后若 a+b<b+a  a排在在前 的规则排序, 如 2  21 因为 212 < 221 所以 排序后为 21  2    to_string() 可以将int 转化为string
 class Solution {
public:
static bool cmp(int a,int b){
string A="";
string B="";
A+=to_string(a);
A+=to_string(b);
B+=to_string(b);
B+=to_string(a); return A<B;
}
string PrintMinNumber(vector<int> numbers) {
string answer="";
sort(numbers.begin(),numbers.end(),cmp);
for(int i=;i<numbers.size();i++){
answer+=to_string(numbers[i]);
}
return answer;
}
};

6.丑数

把只包含因子<spanlang="en-us>">2、<spanlang="en-us>">3和<spanlang="en-us>">5的数称作丑数(<spanlang="en-us>">Ugly Number)。例如<spanlang="en-us>">6、<spanlang="en-us>">8都是丑数,但<spanlang="en-us>">14不是,因为它包含因子<spanlang="en-us>">7。习惯上我们把<spanlang="en-us>">1当做是第一个丑数。求按从小到大的顺序的第<spanlang="en-us>">N个丑数。

分析:所谓一个数m是另一个数n的因子,是指n能被m整除,也就是n%m==0

思路1:尴尬  牛客网超时
根据丑数的定义,丑数只能被2,3,5整除。也就是说如果一个数能被2整除,我们把它连续除以2;如果能被3整除,连续除以3;如果能被5整除,连续除以5.如果最后得到的是1,则就是丑数
 class Solution {
public:
bool IsUglyNumber(int number)
{
while(number%==)
number/=;
while(number%==)
number/=;
while(number%==)
number/=;
if(number==)
return true;
else
return false;
}
int GetUglyNumber_Solution(int index)
{
if(index<=)
return ;
int number=;
int uglyFound=;
while(uglyFound<index)
{
++number;
if(IsUglyNumber(number))
{
++uglyFound;
}
}
return number;
}
};

思路2:创建数组保存已经找到的丑数,用空间换时间

根据丑数的定义, 丑数应该是另一个丑数乘以2、3或者5的结果(1除外)  。因此我们可以创建一个数组,里面的数字是排好序的丑数,每一个丑数都是前面的丑数乘以2、3或者5得到的。  
假设数组中已经有若干个丑数排好序后放在数组中,并且把 已有最大的丑数记做M  ,我们接下来分析如何生成下一个丑数。该丑数肯定是前面某一个丑数乘以2、3或者5的结果,所以我们首先考虑把已有的每个丑数乘以2。在乘以2的时候,可以得到若干个小于等于M的结果。由于是按顺序生成的,小于或者等于M肯定已经在数组中了,我们不需要再考虑;还会得到若干个大于M的结果,但我们只需要第一个大于M的结果,因为我们希望丑数是按照从小到大的顺序生成的,其他更大的结果以后再说。我们把得到的第一个乘以2后大于M的丑数记为M2。同样,我们把已有的每一个丑数乘以3和5,能得到第一个大于M的结果M3和M5。那么下一个丑数应该是M2、M3和M5这三个数的最小者了 。  
前面分析的时候,提到把已有的丑数分别乘以2、3和5。事实上这不是必须的,因为已有的丑数是按照顺序放在数组中的。对乘以2而言,肯定存在某一个丑数T2,排在它之前的每一个乘以2得到的结果都会小于已有最大的丑数,在它之后的每一个丑数乘以2得到的结果都会太大。我们只需要记下这个丑数的位置,同时每次生成新的丑数的时候,取更新这个这个T2.对于乘以3和5而言,也存在着同样的T3和T5。  
 class Solution {
public:
int GetUglyNumber_Solution(int index) {
if(index<=)
return ;
int *pUglyNumber=new int[index];
pUglyNumber[]=;
int NextUglyIndex=;
int *pMutiply2=pUglyNumber;
int *pMutiply3=pUglyNumber;
int *pMutiply5=pUglyNumber; while(NextUglyIndex<index)
{
int min=Min(*pMutiply2*,*pMutiply3*,*pMutiply5*);
pUglyNumber[NextUglyIndex]=min;
while(*pMutiply2*<=pUglyNumber[NextUglyIndex]) //当前最大丑数pUglyNumber[NextUglyIndex]
pMutiply2++;
while(*pMutiply3*<=pUglyNumber[NextUglyIndex])
pMutiply3++;
while(*pMutiply5*<=pUglyNumber[NextUglyIndex])
pMutiply5++;
NextUglyIndex++;
}
int ugly=pUglyNumber[index-];
delete[]pUglyNumber;
return ugly;
} int Min(int a,int b,int c)
{
int min=a;
if(min>b)
min=b;
if(min>c)
min=c;
return min;
}
};

7.第一个只出现一次的字符

在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置 
分析:先在hash表中统计各字母出现次数,第二次扫描直接访问hash表获得次数
 class Solution {
public:
int FirstNotRepeatingChar(string str)
{
if ( str.length() == )
return -;
unsigned int hashTime[] = {};
for(int i =;i<str.length();++i)
hashTime[str[i]]++; for(int i =;i<str.length();++i)
{
if(hashTime[str[i]] == )
return i;
}
return -;
}
};

8.数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5
示例1 
输入
1,2,3,4,5,6,7,0
输出
7
分析:
思路一:直接暴力        会超时
 class Solution {
public:
int InversePairs(vector<int> d) {
int r = ;
for(int i = ; i < d.size(); ++i){
for(int j = ; j < i; ++j) if(d[j] > d[i]) ++r;
}
return r;
}
};
思路二:基于归并的思想
先把数组分隔成子数组,先统计出子数组内部的逆序对的数目,然后再统计出两个相邻子数组之间的逆序对的数目。在统计逆序对的过程中,还需要对数组进行排序,实际上就是归并排序。
 class Solution {
public:
int InversePairs(vector<int> data)
{
int length=data.size();
if(length<=)
return ;
vector<int> copy;
for(int i=;i<length;i++)
copy.push_back(data[i]);
long long count=InversePairsCore(data,copy,,length-);
return count%;
}
long long InversePairsCore(vector<int> &data,vector<int> &copy,int start,int end)
{
if(start==end)
{
copy[start]=data[start];
return ;
}
int length=(end-start)/;
long long left=InversePairsCore(copy,data,start,start+length);
long long right=InversePairsCore(copy,data,start+length+,end);
int i=start+length;
int j=end;
int indexcopy=end;
long long count=;
while(i>=start&&j>=start+length+)
{
if(data[i]>data[j])
{
copy[indexcopy--]=data[i--];
count=count+j-start-length; //count=count+j-(start+length+1)+1;
}
else
{
copy[indexcopy--]=data[j--];
}
}
for(;i>=start;i--)
copy[indexcopy--]=data[i];
for(;j>=start+length+;j--)
copy[indexcopy--]=data[j];
return left+right+count;
}
};

9.两个链表的第一个公共点

输入两个链表,找出他们的第一个公共结点
分析:用两个指针扫描”两个链表“,最终两个指针到达 null 或者到达公共结点。
 /*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode *pHead1, ListNode *pHead2) {
ListNode *p1 = pHead1;
ListNode *p2 = pHead2;
while(p1!=p2)
{
if(p1==NULL)
p1=pHead2;
else
p1=p1->next;
if(p2==NULL)
p2=pHead1;
else
p2=p2->next;
}
return p1;
}
};

剑指offer第五章的更多相关文章

  1. 剑指offer第七章&amp&semi;第八章

    剑指offer第七章&第八章 1.把字符串转换成整数 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数. 数值为0或者字符串不是一个合法的数值则返回0 输入描述: 输入一个字符串 ...

  2. 剑指offer第六章

    剑指offer第六章 1.数字在排序数组中出现的次数 统计一个数字在排序数组中出现的次数.例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在数组中出现了4次,所以输出4 分析:思路1 ...

  3. 剑指offer第四章

    剑指offer第四章 1.二叉树的镜像 二叉树的镜像:输入一个二叉树,输出它的镜像 分析:求树的镜像过程其实就是在遍历树的同时,交换非叶结点的左右子结点. 求镜像的过程:先前序遍历这棵树的每个结点,如 ...

  4. 剑指offer第三章

    剑指offer第三章 1.数值的整数次方 给定一个double类型的浮点数base和int类型的整数exponent.求base的exponent次方. class Solution { public ...

  5. 《剑指Offer》第二章(一)题3-8

    为春招实习做准备,记录一下<剑指Offer>里面的面试题 第二章 面试题3:数组之中的重复数字. 这个题吧,虽然不难,但是不知道为什么就是看了很久,可能很久没有做算法题了.最后面一句话说的 ...

  6. 《剑指Offer》第二章(一)题 9 -12

    第二章 面试题9:用两个栈实现队列 题目:如面试题,给你两个栈, 实现队列的先进先出,即在队列头删除一个元素以及在队列的尾部添加一个元素 思路:这个题的分析感觉很巧妙,从一个具体的例子入手,找出其中的 ...

  7. 剑指offer—第三章高质量代码(o&lpar;1&rpar;时间删除链表节点)

    题目:给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间删除该节点,链表节点与函数的定义如下:struct ListNode{int m_nValue;ListNode* m_pValue ...

  8. 剑指offer—第三章高质量的代码(按顺序打印从1到n位十进制数)

    题目:输入一个数字n,按照顺序打印出1到最大n位十进制数,比如输入3,则打印出1,2,3直到最大的3位数999为止. 本题陷阱:没有考虑到大数的问题. 本题解题思路:将要打印的数字,看成字符串,不足位 ...

  9. 剑指offer—第三章高质量代码(数值的整数次方)

    高质量的代码:容错处理能力,规范性,完整性.尽量展示代码的可扩展型和可维护性. 容错处理能力:特别的输入和处理,异常,资源回收. 规范性:清晰的书写,清晰的布局,合理的命名. 完整性:功能测试,边界测 ...

随机推荐

  1. Security1&colon;Create Login

    Login 用于登陆SQL Server,语法是 -- Syntax for SQL Server CREATE LOGIN login_name { WITH <option_list1&gt ...

  2. LeetCode Total Hamming Distance

    原题链接在这里:https://leetcode.com/problems/total-hamming-distance/ 题目: The Hamming distance between two i ...

  3. Jmeter 中使用非GUI启动进行压力测试

    使用非 GUI 模式,即命令行模式运行 JMeter 测试脚本能够大大缩减所需要的系统资源.使用命令jmeter -n -t <testplan filename> -l <list ...

  4. Bootstrap 4 中 Alerts 实现

    Alert 的使用说明 http://v4-alpha.getbootstrap.com/components/alerts/ JavaScript behavior Triggers Enable ...

  5. docker 使用Data Volume 共享文件

    Adding a data volume You can add a data volume to a container using the -v flag with the docker run  ...

  6. Javaweb项目碰到的问题- Access denied for user &&num;39&semi;root&&num;39&semi;&commat;&&num;39&semi;localhost&&num;39&semi; &lpar;using password&colon; YES&rpar;

    出现未给localhost root用户授权,主要是项目中存在的多个xxx.properties,其中用户名为root的password的值不完全相同导致的,使用eclipse的search 功能找到 ...

  7. Sublime Text 3下C&sol;C&plus;&plus;开发环境搭建

    Sublime Text 3下C/C++开发环境搭建 之前在Linux Mint 17一周使用体验中简单介绍过Sublime Text. 1.Sublime Text 3安装 Ubuntu.Linux ...

  8. hdu 3208 Integer’s Power 筛法

    Integer’s Power Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  9. Android Studio 1&period;1&period;0 &OpenCurlyDoubleQuote;关联源码” 或者&OpenCurlyDoubleQuote;导入源码” &comma;又或者插件包

    其实这博文是废话!为什么呢? 1.如果自己的SDK没有更新相应当前操作版本的source的话,相应的v4,v7等等的源码都不会自动导入的. 其实Android Studio自身就已经会去检测你当前SD ...

  10. insert-delete-getrandom-o1-duplicates-allowed

    https://leetcode.com/problems/insert-delete-getrandom-o1-duplicates-allowed/ public class Randomized ...