# 2022q1 Homework1 (quiz1)
contributed by < `happyjack91630` >
>[作業需求](https://hackmd.io/@sysprog/linux2022-quiz1)
## 第二題 - [LeetCode 82. Remove Duplicates from Sorted List II](https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/)
針對 LeetCode 82. Remove Duplicates from Sorted List II,以下是可能的合法 C 程式實作:
::: success
COND1 = head->next && head->val == head->next.val
COND2 = head->next && head->val == head->next.val
:::
Recursive version
```c=
#include <stddef.h>
struct ListNode {
int val;
struct ListNode *next;
};
struct ListNode *deleteDuplicates(struct ListNode *head)
{
if (!head)
return NULL;
if (COND1) {
/* Remove all duplicate numbers */
while (COND2)
head = head->next;
return deleteDuplicates(head->next);
}
head->next = deleteDuplicates(head->next);
return head;
}
```
這題目的是要將single link-list裡,存在著重複`val`的node都刪掉。
:::info
```c=
if (!head)
return NULL;
```
上述這段是要確保`head`不為`NULL`。
:::
:::info
```c=
if (COND1) {
/* Remove all duplicate numbers */
while (COND2)
head = head->next;
return deleteDuplicates(head->next);
}
```
這段程式碼的**註解**就已經說很明白了,就是要來刪除重覆數值的節點。所以`COND1`一定要比較`head->val和head->next.val`是否相同(但是要確保還有`head->next`不是`NULL`,所以也要比較`head->next != NULL`),如果相同,就進入`if`。但是因為是Sorted list,所以有可能`head->val`也有可能跟`head->next->next.val`相同,所以就利用`while`迴圈來找到最後與`head->val`相同值的節點。因為`head`也是重覆值,所以拿`head->next`做遞迴,去比較下個`head`的情況。
![](https://i.imgur.com/xET4I81.png)
:::
:::info
```c=
head->next = deleteDuplicates(head->next);
return head;
```
`head->val`與`head->next.val`不相同,所以保留`head,head->next = deleteDuplicates(head->next)`。
:::
Iterative version
>參考 kevinshieh0225
```c=
struct ListNode* deleteDuplicates(struct ListNode* head){
if (!head){
return NULL;
}
struct ListNode **cur = &head;
struct ListNode *iter = (*cur)->next;
while(iter){
if(iter && (*cur)->val == iter->val){
while(iter && (*cur)->val == iter->val){
iter = iter->next;
}
*cur = iter;
if(!iter){
break;
}
} else{
cur = &(*cur)->next;
}
iter = iter->next;
}
return head;
}
```
## 第三題 - [LeetCode 146. LRU Cache](https://leetcode.com/problems/lru-cache/)
針對 LeetCode 146. LRU Cache,以下是可能的合法 C 程式實作:
::: success
MM1 = list_for_each_entry_safe
MM2 = list_for_each_entry
MM3 = list_for_each_entry
MM4 = list_last_entry
:::
```c=
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
typedef struct {
int capacity, count;
struct list_head dhead, hheads[];
} LRUCache;
typedef struct {
int key, value;
struct list_head hlink, dlink;
} LRUNode;
LRUCache *lRUCacheCreate(int capacity)
{
LRUCache *obj = malloc(sizeof(*obj) + capacity * sizeof(struct list_head));
obj->count = 0;
obj->capacity = capacity;
INIT_LIST_HEAD(&obj->dhead);
for (int i = 0; i < capacity; i++)
INIT_LIST_HEAD(&obj->hheads[i]);
return obj;
}
void lRUCacheFree(LRUCache *obj)
{
LRUNode *lru, *n;
MMM1 (lru, n, &obj->dhead, dlink) {
list_del(&lru->dlink);
free(lru);
}
free(obj);
}
int lRUCacheGet(LRUCache *obj, int key)
{
LRUNode *lru;
int hash = key % obj->capacity;
MMM2 (lru, &obj->hheads[hash], hlink) {
if (lru->key == key) {
list_move(&lru->dlink, &obj->dhead);
return lru->value;
}
}
return -1;
}
void lRUCachePut(LRUCache *obj, int key, int value)
{
LRUNode *lru;
int hash = key % obj->capacity;
MMM3 (lru, &obj->hheads[hash], hlink) {
if (lru->key == key) {
list_move(&lru->dlink, &obj->dhead);
lru->value = value;
return;
}
}
if (obj->count == obj->capacity) {
lru = MMM4(&obj->dhead, LRUNode, dlink);
list_del(&lru->dlink);
list_del(&lru->hlink);
} else {
lru = malloc(sizeof(LRUNode));
obj->count++;
}
lru->key = key;
list_add(&lru->dlink, &obj->dhead);
list_add(&lru->hlink, &obj->hheads[hash]);
lru->value = value;
}
```
:::info
`MMM1`是在`lRUCacheFree`,顧名思義是要將 cache 裡的東西全部釋放掉。所以必須走訪所有節點,且執行資源釋放,所以MM1 = `list_for_each_entry_safe`
:::
:::info
`MMM2`是在`lRUCacheGet`,顧名思義是要將cache裡找key值。所以必須遍歷所有的東西,如果有找到對應的key,也要將key在link_list裡的位置移到最前面(head)。所以MM2 = `list_for_each_entry`
:::
:::info
`lRUCachePut`,顧名思義是要將`key`,`value`放入。
在`MM3`的for迴圈要表示的是,我原本的list的就已經有要找的值了,所以我只需要將對應key的list往前擺就好了。MM3 = `list_for_each_entry`
在`MM4`的上面的if是要表達,這個list已經額滿了,我們要將最不常用(list最底層的key)踢掉,所以我認為MM4 = `list_last_entry`
:::