哈希表
哈希表(Hash Table):也叫做散列表。是根据关键码值(Key Value)直接进行访问的数据结构。
哈希表通过键 key
和映射函数 Hash(key)
计算出对应的值 value
,把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做哈希函数(散列函数)
,存放记录的数组叫做哈希表(散列表)
。
下面是本周做过的题(节选)(题目来自力扣):
第一题
给定两个字符串 *s*
和 *t*
,编写一个函数来判断 *t*
是否是 *s*
的字母异位词。
**注意:**若 *s*
和 *t*
中每个字符出现的次数都相同,则称 *s*
和 *t*
互为字母异位词。
本题是哈希表中的一道简单题,要判断串s和串t中字母出现次数是否相同,我们只需要把串s和串t中的字母按下标存储起来,再判断是否数量相等。
我们可以把每个字母减’a’,然后再存储。
下面是代码实现:
#include<string.h>
bool isAnagram(char* s, char* t) {
int arr1[27]={0};
int arr2[27]={0};
int i=0;
int lens=strlen(s);
int lent=strlen(t);
if(lens!=lent)
return false;
for(i=0;i<lens;i++){
arr1[s[i]-'a']++;
}
for(i=0;i<lent;i++){
arr2[t[i]-'a']++;
}
for(i=0;i<27;i++){
if(arr1[i]!=arr2[i])
return false;
}
return true;
}
第二题
罗马数字包含以下七种字符: I
, V
, X
, L
,C
,D
和 M
。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2
写做 II
,即为两个并列的 1 。12
写做 XII
,即为 X
+ II
。 27
写做 XXVII
, 即为 XX
+ V
+ II
。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII
,而是 IV
。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX
。这个特殊的规则只适用于以下六种情况:
I
可以放在V
(5) 和X
(10) 的左边,来表示 4 和 9。X
可以放在L
(50) 和C
(100) 的左边,来表示 40 和 90。C
可以放在D
(500) 和M
(1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。
这道题思路是当左边大于右边时用加法,左边小于右边时用减法。
所以我们可以先把字母之间的加减存储起来,然后就能直接使用了。
下面是代码实现:
int romanToInt(char* s) {
int len=strlen(s);
int arr[27]={0};
arr['I'-'A']=1;
arr['V'-'A']=5;
arr['X'-'A']=10;
arr['L'-'A']=50;
arr['C'-'A']=100;
arr['D'-'A']=500;
arr['M'-'A']=1000;
int i=0;
int ans=0;
for(i=0;i<len;i++){
int m=arr[s[i]-'A'];//字母存储时减去'a'
if(i<len-1&&m<arr[s[i+1]-'A'])//首先i要小于len-1,因为之后i要加1。然后再判断前后大小加或减
ans-=m;
else
ans+=m;
}
return ans;
}
第三题
给定两个数组 nums1
和 nums2
,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
我们可以把nums1和nums2分别按下标存储到arr1,arr2里面,然后再判断是否有相同的。我这里想的是arr1,arr2中出现的都设置为1,然后加起来看是否等于2.
下面是代码实现:
int* intersection(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize) {
int arr1[1001]={0};
int arr2[1001]={0};
int arr[1001]={0};
for(int i=0;i<nums1Size;i++){
arr1[nums1[i]]++;
if(arr1[nums1[i]]>=2)
arr1[nums1[i]]=1;//如果大于1,就继续设置为1,这样最后加起来看是否等于2
}
int j=0;
int* ans=(int*)malloc(sizeof(int)*nums2Size);
for(int i=0;i<nums2Size;i++){
arr2[nums2[i]]++;
if(arr2[nums2[i]]>=2)
arr2[nums2[i]]=1;
}
for(int i=0;i<1001;i++){
arr[i]=arr1[i]+arr2[i];//两个数组加起来
}
for(int i=0;i<1001;i++){
if(arr[i]==2){//如果等于2,则证明两个数组有交集
ans[j++]=i;
}
}
*returnSize=j;
return ans;
}
贪心算法
贪心算法总的来说就是以局部最优从而推出全局最优。
但是贪心算法并没有固定的解决套路。
下面是本周做过的题:
第一题
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子 i
,都有一个胃口值 g[i]
,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j
,都有一个尺寸 s[j]
。如果 s[j] >= g[i]
,我们可以将这个饼干 j
分配给孩子 i
,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
我们这道题的思路就是尽量把大的饼干分给胃口大的小孩。
我们可以从大到小循环小孩,从最大的饼干开始的分发,如果大于小孩的胃口,ans++,然后饼干减小。
下面是代码实现:
int cmp(int* a,int* b){
return *a-*b;
}
int findContentChildren(int* g, int gSize, int* s, int sSize) {
qsort(g,gSize,sizeof(int),cmp);
qsort(s,sSize,sizeof(int),cmp);
int ans=0;
int m=sSize-1;
for(int i=gSize-1;i>=0;i--){
if(m>=0&&s[m]>=g[i]){
ans++;
m--;
}
}
return ans;
}
第二题
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 **摆动序列 。**第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。
- 例如,
[1, 7, 4, 9, 2, 5]
是一个 摆动序列 ,因为差值(6, -3, 5, -7, 3)
是正负交替出现的。 - 相反,
[1, 4, 7, 2, 5]
和[1, 7, 4, 5, 5]
不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。
给你一个整数数组 nums
,返回 nums
中作为 摆动序列 的 最长子序列的长度 。
这道题我们主要找拐点,因为他可能会出现平坡或者单点区间
下面是代码实现:
int wiggleMaxLength(int* nums, int numsSize){
if(numsSize<=1)
return numsSize;
int ans=1;
int n=0;
int curDiff = 0;
int preDiff = 0;
for (int i = 0; i < numsSize - 1; i++) {
curDiff = nums[i + 1] - nums[i];//先把i+1减去i存起来,方便之后的判断和向后循环
if ((curDiff > 0 && preDiff <= 0) || (preDiff >= 0 && curDiff < 0)) {//这里判断的是前后异号,即判断是不是为拐点
ans++;//如果是,则ans++
preDiff = curDiff;
}
}
return ans;
}
第三题
给你一个非负整数数组 nums
,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标,如果可以,返回 true
;否则,返回 false
。
我们只需要判断数组能否覆盖到最后一个,就可以得出结论
下面是代码实现:
bool canJump(int* nums, int numsSize) {
if(numsSize<=1)
return true;
int cover=0;
for(int i=0;i<=cover;i++){//如果中间断了,则跳出循环
cover=fmax(cover,i+nums[i]);//cover储存的是能覆盖的到的最大范围
if(cover>=numsSize-1)//这里判断的是能否覆盖到最后一位
return true;
}
return false;
}
小结
关于算法的掌握还是需要多多练题,多见不同的题型我们才能够更加熟悉本算法。本周做了多道算法题,在之后的学习中也会继续练习。
已经到底啦!!