《剑指offer》系列第二弹,让我们用饱满的热情,迎接接下来的几道小题。 >本系列分享的都是常规做法和全新思路的总结,各位可千万不要看着眼熟,而错过新颖的思路噻!!!
文章目录
1.将数组中出现次数超过一半的数字返回
(1)采用unordered_map方式
这应该是在我们学习了C++等相关知识后,最方便的一种做法。
代码和注释代表思路如下: 先找到keyi值,如果是首次出现就设置次数为1,不是第一次就++次数
。
#include<unordered_map>
int MoreThanHalfNum_Solution(vector<int > numbers)
{
int half=numbers.size()/2;//先拿到一半的个数是多少
unordered_map<int,int> map;//采用<数字,次数>的映射关系,最后统计出现的次数
//想要统计个数就涉及到遍历
for(int i=0;i<numbers.size();++i)
{
auto it=map.find(numbers[i]);//找到keyi值
if(it==map.end())//如果没有找到,就首次进行插入
{
//在i的位置,次数加为1,表示第一次出现
map.insert({numbers[i],1});
}
else//如果不是第一次出现,次数就++
{
map[numbers[i]]++;
}
if(map[numbers[i]]>half)
return numbers[i];
}
return 0;
}
(2)先排序再找中间位置元素记录次数进行验证
这个方式的思路就是:
如果他的次数大于一半,那么在进行排序之后中间元素就一定是内个次数大于一半的,
然后再遍历一遍验证这个元素的个数是否大于一半。
int MoreThanHalfNum_Solution(vector<int > numbers)
{
sort(numbers.begin(),numbers.end());
int target=numbers[numbers.size()/2];
int count=0;
for(int i=0;i<numbers.size();++i)
{
if(target==numbers[i])
count++;
}
if(count>numbers.size()/2)
return target;
return 0;
}
(3)候选法,两个不同的数据相消减
思路:既然出现次数大于一半,如果两个元素不相同,
那么我选择一换一的方式对于数组进行抵消,剩下的内个就是最多的内个。
具体实现:cond:就是值,cnt就是次数,通过对于众数次数的–,实现相消的效果。
遇到不同的就减减。
int MoreThanHalfNum_Solution2(vector<int> numbers)
{
int cond = -1;
int cnt = 0;
for (int i = 0; i < numbers.size(); ++i)
{
if (cnt == 0)
//这个cnt就是此时众数和非众数继续相消所剩下的个数。
//如果消减只剩下0,就说明前面的区间消除完毕,继续消减后面的
//反正众数就是比非众数多
{
cond = numbers[i];
++cnt;
}
else//相同就++,不同就--,基础就是众数的存在,在两两相消的进程中,总会剩下一个。
{
if (cond == numbers[i])
++cnt;
else
--cnt;
}
}
//得到cond数字,然后进行数出现的次数
cnt = 0;
for (const int k : numbers)
{
if (cond == k)
++cnt;
}
if (cnt > numbers.size() / 2)
return cond;
return 0;
}
2. 将字符串中的空格替换成 %20
一个空格是一个字符,替换成的这个是三个字符。(因题而异),那么我们想的就是当遇到空格的时候就进行替换,就涉及到扩容的问题,扩几个的问题。
指针示意图如下:
void replaceSpace(char* str,int length)
{
int count=0;
char* start=str;
//记录,空格的次数,便于扩充之后新的尾指针的确定
while(*start)
{
if(isspace(*start))//如果是空格,就记录空格的次数
{
count++;
}
start++;
}
char *old_end =str+length;
char* new_end=str+length+2*count;
while(old_end>=str&&new_end>=str)
{
if(isspace(*old_end))
{
*new_end=*old_end;
//将不是空格的字符向后移动,以便给插入字符留出空间
new_end--,old_end--;
}
else
{
//先赋值,再往前移动位置
*new_end--='0';
*new_end--='2';
*new_end--='%';
old_end--;
}
}
}
3.递归的思路实现单链表的逆序打印
递归的方式实现 递归返回的时候实现打印或者内容的保存
不理解的bro 可以画个图理解一下
void Fprint(ListNode listnode, ArrayList<Integer>list)
{
if(listNode==NULL)
return ;
Fprint(listnode .next,list);
list.add(listnode.val);
}
ArrayList<Integer>print(ListNode listnode)
{
ArrayList<Integer> list=new ArrayList<>();
Fprint(listnode,list);
return list;
}
手绘图如下:
4. 大郎,喝鸡汤了!!!
人生的精彩,就在于接下来的每一个场景都有他的未知性。或许在某一个瞬间,或许某一个场景,遇到的某一个人发生的某一个事都会给你心灵上的安慰。如春风般沐浴,如夏雨般滋润我们的心田。
让我们热爱生活,认真走好每一步。诗意般的远方就会越来越近。
Fighting!my bro!