LeetCode 667 键值映射 C语言
实现一个 MapSum 类里的两个方法,insert 和 sum。
对于方法 insert,你将得到一对(字符串,整数)的键值对。字符串表示键,整数表示值。如果键已经存在,那么原来的键值对将被替代成新的键值对。
对于方法 sum,你将得到一个表示前缀的字符串,你需要返回所有以该前缀开头的键的值的总和。
示例 1:
输入: insert(“apple”, 3), 输出: Null
输入: sum(“ap”), 输出: 3
输入: insert(“app”, 2), 输出: Null
输入: sum(“ap”), 输出: 5
什么是键值?String str=“test”; str是一个引用,以地址的形式存储在栈中,相当于键值对中的键,而"test"是存储在内存堆中的一个值,想当于键值对中的值。概念很广,有点线性映射的样子。
思路1:前缀树https://blog.youkuaiyun.com/qq_40405527/article/details/108044311
#define Num 26
typedef struct mapsum{
int isEnd;
int val;
struct mapsum* next[Num];
} MapSum;
/** Initialize your data structure here. */
MapSum* mapSumCreate() {
MapSum* root = (MapSum*)malloc(sizeof(MapSum));
memset(root, 0, sizeof(MapSum));
return root;
}
void mapSumInsert(MapSum* obj, char * key, int val) {
MapSum* root = obj;
int len = strlen(key);
int index = 0;
for(int i=0;i<len;i++) {
index = key[i] - 'a';
if(root->next[index]==NULL) {
root->next[index] = mapSumCreate();
}
root = root->next[index];
}
root->isEnd = true;
root->val = val;
}
int sum_all_prefix(MapSum* obj){
if(obj==NULL)
return 0;
int res = obj->val;
for(int i=0;i<Num;i++) {
res += sum_all_prefix(obj->next[i]);
}
return res;
}
int mapSumSum(MapSum* obj, char * prefix) {
MapSum* root = obj;
int len = strlen(prefix);
int index = 0;
for(int i=0;i<len;i++) {
index = prefix[i] - 'a';
if(root->next[index]!=NULL) {
root = root->next[index];
} else
return 0; //没有该前缀
}
return sum_all_prefix(root);//去找所有该前缀结尾的值
}
void mapSumFree(MapSum *obj){
MapSum *root = obj;
for(int i=0;i<Num;i++){
if(root->next[i] != NULL)
mapSumFree(root->next[i]);
}
free(root);
}
思路2:常规解题
1: 首先是创建MapSum_Create()一个指向结构体Struct ListNode 的头结点 root
2: 接着是插入void MapSum_Insert(MapSum * obj,char *str, int val)
2.1 判断是否有相同键值struct List_node *find_node_in_list(MapSum *obj,char *str):以obj->node为起点判断是否为空,
如果不为空,判断该节点的node->str与传参str是否一致,如果相同,则返回该节点;否则指向下一个节点(strcmp的参数不能为NULL,所以当传参节点的str为空时,指向下一节点跳出本次循环)
如果为空,则直接返回,代表没有找到相同键
2.2 寻找最后一个非空节点struct List_node *get_last_node(MapSum *obj),用于寻找节点插入的位置,以obj->node为起点为判断:
如果不为空,则循环查找,如果为空则代表是头结点
find_node_in_list如果没有找到相同键,则分配空间存放新的键;如果找到了,则修改该节点的值;get_last_node如果是空,新节点插入在头结点后;非空,则插入在最后一个节点后;
3: 统计前缀相同的键值和int MapSum_Sum(MapSum *obj,char *prefix);以obj->node为起点判断
利用strncmp以前缀字符串的长度判断是否一致;如果一致则统计总和sum值
4: 释放void MapSum_free(MapSum *obj)以及void list_free(List_node *temp_node)
递归调用list_free从尾节点开始释放,结束后释放头文件root
#include <string.h>
#include <stdlib.h>
struct list_node {
struct list_node* next;
char* str;
int val;
};
typedef struct {
struct list_node* node;
} MapSum;
/** Initialize your data structure here. */
MapSum* mapSumCreate() {
MapSum * root = (MapSum *)malloc(sizeof(MapSum));
memset(root,0,sizeof(MapSum));
return root;
}
struct list_node* find_node_in_list(char* str, MapSum* obj)
{
struct list_node* find_node = obj->node;
while (find_node != NULL) {
if (find_node->str == NULL) {
find_node = find_node->next;
continue;
}
if (strcmp(find_node->str, str) == 0) {
return find_node;
} else {
find_node = find_node->next;
}
}
return find_node;
}
struct list_node* get_last_node(MapSum* obj)
{
struct list_node* temp_node = obj->node;
while (temp_node != NULL) {
if (temp_node->next == NULL) {
return temp_node;
}
temp_node = temp_node->next;
}
return temp_node;
}
void mapSumInsert(MapSum* obj, char * str, int val) {
struct list_node* node = NULL;
size_t len = 0;
struct list_node* last_node = NULL;
if (obj == NULL || str == NULL) {
return;
}
node = find_node_in_list(str, obj);
if (node == NULL) {
node = (struct list_node*)malloc(sizeof(struct list_node));
#if 1
if (node == NULL) {
return;
}
memset(node, 0, sizeof(struct list_node));
last_node = get_last_node(obj);
if (last_node == NULL) {
obj->node = node;
} else {
last_node->next = node;
}
#endif
}
if (node->str == NULL) {
len = strlen(str) + 1;
node->str = (char*)malloc(len);
strcpy(node->str, str);
}
node->val = val;
}
int mapSumSum(MapSum* obj, char * prefix) {
size_t len = 0;
int sum = 0;
struct list_node* temp_node = obj->node;
if (obj == NULL || prefix == NULL) {
return sum;
}
len = strlen(prefix);
while (temp_node != NULL) {
if (strncmp(temp_node->str, prefix, len) == 0) {
sum += temp_node->val;
}
temp_node = temp_node->next;
}
return sum;
}
void list_free(struct list_node* temp_node)
{
if (temp_node == NULL) {
return;
}
list_free(temp_node->next);
free(temp_node->str);
temp_node->str = NULL;
free(temp_node);
temp_node = NULL;
}
void mapSumFree(MapSum* obj) {
if (obj == NULL) {
return;
}
list_free(obj->node);
free(obj);
}
/*
Map_key.c
以下是在ubuntu 14.04下能实现功能的代码
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct List_node{
struct List_node *next;
char *str;
int val;
};
typedef struct{
struct List_node *node;
}MapSum;
//MapSum g_list_head = {0};
MapSum * MapSum_Create(){
MapSum * root =(MapSum*)malloc(sizeof(MapSum));
//return &g_list_head;
return root;
}
struct List_node * find_node_in_list(char * str,MapSum *obj){
struct List_node * find_node = obj->node;
while(find_node != NULL){
if(find_node->str == NULL){
find_node = find_node->next;
continue;
}
if(strcmp(find_node->str,str)==0){//找到相同键则返回该节点
return find_node;
}
else{
find_node = find_node->next; //没有找到则继续,直到尾节点
}
}
return find_node;
}
struct List_node* get_last_node(MapSum * obj){
struct List_node * temp_node = obj->node;
while(temp_node != NULL){ //找到最后一个非空的节点
if(temp_node->next == NULL){
return temp_node;
}
temp_node = temp_node->next;
}
return temp_node;
}
void MapSum_Insert(MapSum *obj, char *str,int val){
struct List_node * node = NULL;
int len;
struct List_node * last_node = NULL;
if(obj == NULL || str == NULL){
return;
}
node = find_node_in_list(str,obj);
if(node == NULL){//没有找到相同的键,则分配空间存放下一节点
node = (struct List_node *)malloc(sizeof(struct List_node));
if(node == NULL){
return;
}
memset(node,0,sizeof(struct List_node));
last_node = get_last_node(obj);//找到最后一个非空的节点 插入node
if(last_node == NULL){
obj->node = node;//如果为空,为根节点
}
else{
last_node->next = node;
}
}
if(node->str == NULL){//如果没有找到相同键,分配新空间的str为空
len = strlen(str)+1;
node->str = (char *)malloc(len);
strcpy(node->str,str);
node->val = val;
printf("没有找到相同键,插入新键%s\n",str);
}
else{
node->val = val;//如果存在相同键覆盖,不存在则赋值
printf("找到相同键%s,修改值为%d\n",str,val);
}
}
int MapSum_Sum(MapSum * obj,char * prefix){
int len=0;
int sum=0;
struct List_node * temp_node = obj->node;
if(obj==NULL || prefix==NULL){
return sum;
}
len = strlen(prefix);
while(temp_node != NULL){
if(strncmp(temp_node->str,prefix,len)==0){//比较前缀与键值的前len个字符
sum += temp_node->val;
}
temp_node = temp_node->next;
}
return sum;
}
#if 0
void List_free(struct List_node ** temp_node){
if(temp_node == NULL){
return;
}//递归释放空间
List_free(&(*temp_node)->next);//释放node->str的空间
printf("准备释放释放键%s\n",(*temp_node)->str);
free((*temp_node)->str);
(*temp_node)->str=NULL;
free(*temp_node);
*temp_node =NULL;
}
#endif
void list_free(struct List_node * temp_node){
if(temp_node == NULL)
return;
list_free(temp_node->next);
printf("准备释放键%s\n",temp_node->str);
free(temp_node->str);
printf("准备释放节点\n");
free(temp_node);
temp_node=NULL;
}
void MapSum_free(MapSum * obj){
if(obj == NULL){
return;
}
// List_free(&obj->node);
list_free(obj->node);
printf("准备释放根结点\n");
free(obj);
printf("释放结束\n");
}
void main(){
MapSum * root =MapSum_Create();
MapSum_Insert(root,"apple",3);
printf("\"ap\"前缀的值总和为%d\n",MapSum_Sum(root,"ap"));
MapSum_Insert(root,"app",2);
printf("\"ap\"前缀的值总和为%d\n",MapSum_Sum(root,"ap"));
MapSum_Insert(root,"app",3);
MapSum_Insert(root,"pp",3);
printf("\"ap\"前缀的值总和为%d\n",MapSum_Sum(root,"ap"));
MapSum_free(root);
}