编程总结
在刷题之前需要反复练习的编程技巧,尤其是手写各类数据结构实现,它们好比就是全真教的上乘武功
手写完成后,我们针对性的进行练习,练习题如下:
1603. 设计停车系统
379. 电话目录管理系统
1396. 设计地铁系统
1427. 设计浏览器历史记录
635. 设计日志存储系统
1. 入门
1603. 设计停车系统
数据结构
typedef struct {
int bigCar;
int mediumCar;
int smallCar;
} ParkingSystem;
主函数
// 1.建立停车系统
ParkingSystem *parkingSystemCreate(int bigCar, int mediumCar, int smallCar)
{
ParkingSystem *sys = (ParkingSystem *)malloc(sizeof(ParkingSystem));
sys->bigCar = bigCar;
sys->mediumCar = mediumCar;
sys->smallCar = smallCar;
return sys;
}
// 2.增加汽车停车
bool parkingSystemAddCar(ParkingSystem *obj, int carType)
{
if (carType == 1) {
if (obj->bigCar > 0) {
obj->bigCar--;
} else {
return false;
}
} else if (carType == 2) {
if (obj->mediumCar > 0) {
obj->mediumCar--;
} else {
return false;
}
} else if (carType == 3) {
if (obj->smallCar > 0) {
obj->smallCar--;
} else {
return false;
}
} else {
return false;
}
return true;
}
// 3.释放汽车停车系统
void parkingSystemFree(ParkingSystem *obj)
{
free(obj);
}
2. 栈与队列
1427. 设计浏览器历史记录
typedef struct {
int top;
int cur;
char url[5001][21];
} BrowserHistory;
BrowserHistory *browserHistoryCreate(char *homepage)
{
BrowserHistory *obj = (BrowserHistory *)malloc(sizeof(BrowserHistory));
obj->top = -1;
obj->top++;
obj->cur = obj->top;
strcpy(obj->url[obj->cur], homepage);
return obj;
}
void browserHistoryVisit(BrowserHistory *obj, char *url)
{
obj->cur++;
strcpy(obj->url[obj->cur], url);
obj->top = obj->cur; // 将浏览历史前进的记录删除,更新了Top
}
char *browserHistoryBack(BrowserHistory *obj, int steps)
{
if (steps > obj->cur) {
steps = obj->cur;
}
obj->cur = obj->cur - steps;
return obj->url[obj->cur];
}
char *browserHistoryForward(BrowserHistory *obj, int steps)
{
if ((obj->top - obj->cur) < steps) {
steps = obj->top - obj->cur;
}
obj->cur = obj->cur + steps;
return obj->url[obj->cur];
}
void browserHistoryFree(BrowserHistory *obj)
{
free(obj);
}
3. 哈希
705. 设计哈希集合
typedef struct {
int hash[1000001];
} MyHashSet;
MyHashSet *myHashSetCreate()
{
MyHashSet *obj = (MyHashSet *)calloc(sizeof(MyHashSet), 1);
return obj;
}
void myHashSetAdd(MyHashSet *obj, int key)
{
obj->hash[key] = 1;
}
void myHashSetRemove(MyHashSet *obj, int key)
{
obj->hash[key] = 0;
}
bool myHashSetContains(MyHashSet *obj, int key)
{
return obj->hash[key];
}
void myHashSetFree(MyHashSet *obj)
{
free(obj);
}
379. 电话目录管理系统
1. get: 分配给用户一个未被使用的电话号码,获取失败请返回 -1
2. check: 检查指定的电话号码是否被使用
3. release: 释放掉一个电话号码,使其能够重新被分配
数据结构
#define PHONE_OCCUPY 2 // 未被使用赋值为 2,已占用赋值为1
#define PHONE_FREE 1
// 号码节点的定义
typedef struct Node_t {
int valid;
int val;
} Node;
// 电话目录的定义
typedef struct {
Node *node;
int capacity;
} PhoneDirectory;
主函数
// 1.电话目录的初始化
PhoneDirectory *phoneDirectoryCreate(int maxNumbers)
{
PhoneDirectory *obj = (PhoneDirectory *)malloc(sizeof(PhoneDirectory));
obj->node = (Node *)malloc(sizeof(Node) * maxNumbers);
for (int i = 0; i < maxNumbers; i++) {
obj->node[i].valid = PHONE_FREE;
obj->node[i].val = i;
obj->capacity = maxNumbers;
}
return obj;
}
// 2.分配用户一个号码
int phoneDirectoryGet(PhoneDirectory *obj)
{
for (int i = 0; i < obj->capacity; i++) {
if (obj->node[i].valid == PHONE_FREE) {
obj->node[i].valid = PHONE_OCCUPY;
return obj->node[i].val;
}
}
return -1;
}
// 3.检查指定号码是否被使用
bool phoneDirectoryCheck(PhoneDirectory *obj, int number)
{
for (int i = 0; i < obj->capacity; i++) {
if (obj->node[i].valid == PHONE_FREE && obj->node[i].val == number) {
return true;
}
}
return false;
}
// 4.释放特定的号码
void phoneDirectoryRelease(PhoneDirectory *obj, int number)
{
for (int i = 0; i < obj->capacity; i++) {
if (obj->node[i].valid == PHONE_OCCUPY && obj->node[i].val == number) {
obj->node[i].valid = PHONE_FREE;
return;
}
}
return;
}
// 5.回收
void phoneDirectoryFree(PhoneDirectory *obj)
{
memset(obj->node, 0, sizeof(Node) * obj->capacity);
free(obj->node);
free(obj);
}
1396. 设计地铁系统
数据结构
#define MAX_SIZE 10000
#define STANAME_LEN 12
// 乘客结构体
typedef struct {
int passenger_id;
char start_station[STANAME_LEN];
char end_station[STANAME_LEN];
double start_time;
double end_time;
} Passenger;
// 地铁系统
typedef struct {
int passenger_num;
Passenger passenger[MAX_SIZE];
} UndergroundSystem;
主函数
// 创建地铁系统
UndergroundSystem *undergroundSystemCreate()
{
UndergroundSystem *obj = (UndergroundSystem *)malloc(sizeof(UndergroundSystem) * 1);
memset(obj, 0, sizeof(UndergroundSystem));
if (!obj) {
return NULL;
}
obj->passenger_num = 0;
return obj;
}
// 通行卡ID等于id的乘客,在时间t,从stationName站进入
void undergroundSystemCheckIn(UndergroundSystem *obj, int id, char *stationName, int t)
{
obj->passenger[obj->passenger_num].passenger_id = id;
strcpy(obj->passenger[obj->passenger_num].start_station, stationName);
obj->passenger[obj->passenger_num].start_time = t;
obj->passenger_num++;
return;
}
// 通行卡ID等于id的乘客,在时间t,从stationName站离开
void undergroundSystemCheckOut(UndergroundSystem *obj, int id, char *stationName, int t)
{
int pnum = obj->passenger_num;
// 找到id的乘客
for (int i = 0; i < obj->passenger_num; i++) {
if (obj->passenger[i].passenger_id == id) {
if (obj->passenger[i].end_station[0] != '\0') {
continue;
}
pnum = i;
break;
}
}
// 如果找到的ID合法,则记录下离开站与时间
if (pnum != obj->passenger_num) {
strcpy(obj->passenger[pnum].end_station, stationName);
obj->passenger[pnum].end_time = t;
}
return;
}
// 返回从startStation站到endStation站的平均时间
double undergroundSystemGetAverageTime(UndergroundSystem *obj, char *startStation, char *endStation)
{
double num = 0.0;
double sum = 0.0;
for (int i = 0; i < obj->passenger_num; i++) {
if (!strcmp(startStation, obj->passenger[i].start_station)
&& !strcmp(endStation, obj->passenger[i].end_station)) {
num++;
sum += obj->passenger[i].end_time - obj->passenger[i].start_time;
}
}
return sum / num;
}
// 释放
void undergroundSystemFree(UndergroundSystem* obj)
{
free(obj);
return;
}
635. 设计日志存储系统
strncmp 总结需要
这题巧用了 strncmp 函数,用来比较带size的字符串,且
int strncmp(const char *str1, const char *str2, size_t n);
// 如果返回值 < 0,则表示 str2 大于 str1
// 如果返回值 > 0,则表示 str2 小于 str1
数据结构
#define MAXSIZE 500
// 日志存储数据结构
typedef struct {
char *timeStamp[MAXSIZE];
int id[MAXSIZE];
int count;
} LogSystem;
主函数
// 初始化LogSystem对象
LogSystem *logSystemCreate(void)
{
LogSystem *gLogsys = (LogSystem *)malloc(sizeof(LogSystem));
gLogsys->count = 0;
memset(gLogsys, 0, sizeof(LogSystem));
for (int i = 0; i < MAXSIZE; i++) {
gLogsys->timeStamp[i] = (char *)malloc(sizeof(char) * (MAXSIZE));
memset(gLogsys->timeStamp[i], 0, sizeof(char) * (MAXSIZE));
}
return gLogsys;
}
// 给定日志的id和timestamp,将这个日志存入你的存储系统中
void logSystemPut(LogSystem *obj, int id, char *timestamp)
{
obj->id[obj->count] = id;
memcpy(obj->timeStamp[obj->count], timestamp, strlen(timestamp) + 1);
obj->count++;
return;
}
// 检索给定时间区间[start, end](包含两端)内的所有日志的id
int *logSystemRetrieve(LogSystem *obj, char *start, char *end, char *granularity, int *retSize)
{
int i;
int len = 0;
char *classification[6] = { "Year", "Month", "Day", "Hour", "Minute", "Second" };
int classLength[6] = { 4, 7, 10, 13, 16, 19 }; // 上述时间的字符串长度
for (i = 0; i < 6; i++) {
// granularity表示考虑的时间粒度(例如,精确到 Day、Minute 等)
if (strcmp(granularity, classification[i]) == 0) {
len = classLength[i];
break;
}
}
int *ret = (int *)malloc(sizeof(int) * (obj->count));
memset(ret, 0, sizeof(int)*obj->count);
// 如果返回值 < 0,则表示 str2 大于 str1
// 如果返回值 > 0,则表示 str2 小于 str1
for (i = obj->count; i >= 0; i--) { // 由于题目要求输出的顺序,所以这里从后往前了.
if (strncmp(start, obj->timeStamp[i], len) <= 0 && strncmp(end, obj->timeStamp[i], len) >= 0) {
ret[(*retSize)++] = obj->id[i];
}
}
return ret;
}
void logSystemFree(LogSystem *obj)
{
memset(obj, 0, sizeof(LogSystem));
obj->count = 0;
}
4. 缓存
146. LRU 缓存机制
typedef struct {
int key;
int val;
UT_hash_handle hh;
} LRUCache;
LRUCache *g_usr = NULL;
int g_size;
// 1.初始化
LRUCache *lRUCacheCreate(int capacity)
{
g_size = capacity;
return g_usr;
}
// 2.如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1
int lRUCacheGet(LRUCache *obj, int key)
{
LRUCache *cur_usr = NULL;
HASH_FIND_INT(g_usr, &key, cur_usr);
// 因为链表表头存的是最久为使用的数据,所以get一次就要把它更新到链表末尾
if (cur_usr != NULL) { // get存在的key,则该key被使用了一次,因此需要先删后入,满足LRU
HASH_DEL(g_usr, cur_usr);
HASH_ADD_INT(g_usr, key, cur_usr);
return cur_usr->val;
}
// 如果没有找到,则返回-1
return -1;
}
// 3.如果关键字 key 已经存在,则变更其数据值 value
void lRUCachePut(LRUCache *obj, int key, int value)
{
LRUCache *cur_usr = NULL, *next_usr = NULL;
HASH_FIND_INT(g_usr, &key, cur_usr);
if (cur_usr != NULL) {
HASH_DEL(g_usr, cur_usr);
cur_usr->key = key;
cur_usr->val = value;
HASH_ADD_INT(g_usr, key, cur_usr);
} else { // 新插入
int cnt = HASH_COUNT(g_usr);
// 如果已经满size了
if (cnt == g_size) { // 这段的含义
HASH_ITER(hh, g_usr, cur_usr, next_usr) {
HASH_DEL(g_usr, cur_usr);
free(cur_usr);
break;
}
}
LRUCache *new_usr = (LRUCache *)malloc(sizeof(LRUCache));
new_usr->key = key;
new_usr->val = value;
HASH_ADD_INT(g_usr, key, new_usr);
}
return;
}
void lRUCacheFree(LRUCache *obj)
{
LRUCache *cur_usr = NULL, *next_usr = NULL;
HASH_ITER(hh, g_usr, cur_usr, next_usr) {
HASH_DEL(g_usr, cur_usr);
free(cur_usr);
}
}