diff --git a/problems/0203.移除链表元素.md b/problems/0203.移除链表元素.md index f6b5ef6d..c2f1d449 100644 --- a/problems/0203.移除链表元素.md +++ b/problems/0203.移除链表元素.md @@ -737,7 +737,45 @@ public class Solution } } ``` +### Ruby# +```ruby +# 定义链表节点 +class ListNode + attr_accessor :val, :next + def initialize(val = 0, _next = nil) + @val = val + @next = _next + end +end + +# 删除链表中值为 val 的节点 +def remove_elements(head, val) + # 创建一个虚拟头节点,这样可以简化删除头节点的处理 + # 虚拟头节点的值为 0,指向当前链表的头节点 + dummy = ListNode.new(0) + dummy.next = head + + # 初始化当前节点为虚拟头节点 + current = dummy + + # 遍历链表,直到当前节点的下一个节点为空 + while current.next + # 如果当前节点的下一个节点的值等于 val + if current.next.val == val + # 跳过该节点,即将当前节点的 next 指向下一个节点的 next + current.next = current.next.next + else + # 否则继续遍历,当前节点向前移动 + current = current.next + end + end + + # 返回删除 val 后的新链表的头节点,虚拟头节点的 next 就是新的头节点 + dummy.next +end + +```

diff --git a/problems/kamacoder/0126.骑士的攻击astar.md b/problems/kamacoder/0126.骑士的攻击astar.md index 6ea6ca83..a6d45667 100644 --- a/problems/kamacoder/0126.骑士的攻击astar.md +++ b/problems/kamacoder/0126.骑士的攻击astar.md @@ -514,7 +514,170 @@ main() ### C - +```C +#include +#include +#include + +// 定义一个结构体,表示棋盘上骑士的位置和相关的 A* 算法参数 +typedef struct { + int x, y; // 骑士在棋盘上的坐标 + int g; // 从起点到当前节点的实际消耗 + int h; // 从当前节点到目标节点的估计消耗(启发式函数值) + int f; // 总的估计消耗(f = g + h) +} Knight; + +#define MAX_HEAP_SIZE 2000000 // 假设优先队列的最大容量 + +// 定义一个优先队列,使用最小堆来实现 A* 算法中的 Open 列表 +typedef struct { + Knight data[MAX_HEAP_SIZE]; + int size; +} PriorityQueue; + +// 初始化优先队列 +void initQueue(PriorityQueue *pq) { + pq->size = 0; +} + +// 将骑士节点插入优先队列 +void push(PriorityQueue *pq, Knight k) { + if (pq->size >= MAX_HEAP_SIZE) { + // 堆已满,无法插入新节点 + return; + } + int i = pq->size++; + pq->data[i] = k; + // 上滤操作,维护最小堆的性质,使得 f 值最小的节点在堆顶 + while (i > 0) { + int parent = (i - 1) / 2; + if (pq->data[parent].f <= pq->data[i].f) { + break; + } + // 交换父节点和当前节点 + Knight temp = pq->data[parent]; + pq->data[parent] = pq->data[i]; + pq->data[i] = temp; + i = parent; + } +} + +// 从优先队列中弹出 f 值最小的骑士节点 +Knight pop(PriorityQueue *pq) { + Knight min = pq->data[0]; + pq->size--; + pq->data[0] = pq->data[pq->size]; + // 下滤操作,维护最小堆的性质 + int i = 0; + while (1) { + int left = 2 * i + 1; + int right = 2 * i + 2; + int smallest = i; + if (left < pq->size && pq->data[left].f < pq->data[smallest].f) { + smallest = left; + } + if (right < pq->size && pq->data[right].f < pq->data[smallest].f) { + smallest = right; + } + if (smallest == i) { + break; + } + // 交换当前节点与最小子节点 + Knight temp = pq->data[smallest]; + pq->data[smallest] = pq->data[i]; + pq->data[i] = temp; + i = smallest; + } + return min; +} + +// 判断优先队列是否为空 +int isEmpty(PriorityQueue *pq) { + return pq->size == 0; +} + +// 启发式函数:计算从当前位置到目标位置的欧几里得距离的平方(避免开方,提高效率) +int heuristic(int x, int y, int goal_x, int goal_y) { + int dx = x - goal_x; + int dy = y - goal_y; + return dx * dx + dy * dy; // 欧几里得距离的平方 +} + +// 用于记录从起点到棋盘上每个位置的最小移动次数 +int moves[1001][1001]; + +// 骑士在棋盘上的8个可能移动方向 +int dir[8][2] = { + {-2, -1}, {-2, 1}, {-1, 2}, {1, 2}, + {2, 1}, {2, -1}, {1, -2}, {-1, -2} +}; + +// 使用 A* 算法寻找从起点到目标点的最短路径 +int astar(int start_x, int start_y, int goal_x, int goal_y) { + PriorityQueue pq; + initQueue(&pq); + + // 初始化 moves 数组,-1 表示未访问过的位置 + memset(moves, -1, sizeof(moves)); + moves[start_x][start_y] = 0; // 起点位置的移动次数为 0 + + // 初始化起始节点 + Knight start; + start.x = start_x; + start.y = start_y; + start.g = 0; + start.h = heuristic(start_x, start_y, goal_x, goal_y); + start.f = start.g + start.h; // 总的估计消耗 + + push(&pq, start); // 将起始节点加入优先队列 + + while (!isEmpty(&pq)) { + Knight current = pop(&pq); // 取出 f 值最小的节点 + + // 如果已经到达目标位置,返回所需的最小移动次数 + if (current.x == goal_x && current.y == goal_y) { + return moves[current.x][current.y]; + } + + // 遍历当前节点的所有可能移动方向 + for (int i = 0; i < 8; i++) { + int nx = current.x + dir[i][0]; + int ny = current.y + dir[i][1]; + + // 检查新位置是否在棋盘范围内且未被访问过 + if (nx >= 1 && nx <= 1000 && ny >= 1 && ny <= 1000 && moves[nx][ny] == -1) { + moves[nx][ny] = moves[current.x][current.y] + 1; // 更新移动次数 + + // 创建新节点,表示骑士移动到的新位置 + Knight neighbor; + neighbor.x = nx; + neighbor.y = ny; + neighbor.g = current.g + 5; // 每次移动的消耗为 5(骑士移动的距离平方) + neighbor.h = heuristic(nx, ny, goal_x, goal_y); + neighbor.f = neighbor.g + neighbor.h; + + push(&pq, neighbor); // 将新节点加入优先队列 + } + } + } + + return -1; // 如果无法到达目标位置,返回 -1 +} + +int main() { + int n; + scanf("%d", &n); + while (n--) { + int a1, a2, b1, b2; // 起点和目标点的坐标 + scanf("%d %d %d %d", &a1, &a2, &b1, &b2); + + int result = astar(a1, a2, b1, b2); // 使用 A* 算法计算最短路径 + printf("%d\n", result); // 输出最小移动次数 + } + return 0; +} + +```