LeetCode刷题总结(C语言版)_图类

编程总结

每每刷完一道题后,其思想和精妙之处没有地方记录,本篇博客用以记录刷题过程中的遇到的算法和技巧

279)完全平方数
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

#include <stdio.h>
#include <string.h>
#include <stdlib.h> 

// 队列 && BFS
struct Link
{
    int data;
    struct Link* next;
};
 
struct Queue
{
    struct Link *front; // 队头删除
    struct Link *rear;  // 队尾新增
    int size;
};
 
void QueueInit(struct Queue *queue)
{
    queue->front = NULL;
    queue->rear  = NULL;
    queue->size  = 0;
}
 
int QueueEmpty(struct Queue *queue)
{
    return (queue->size == 0);
}
 
void QueuePush(struct Queue *queue, const int data)
{
    struct Link *node;
    node = (struct Link *)malloc(sizeof(struct Link));
    
    node->data = data;
    node->next = NULL;
	printf("push queue %d\n", data);
    
    if (QueueEmpty(queue)) {
        queue->front = node;
        queue->rear = node;
    } else {            
        queue->rear->next = node; // 往队尾增加一个元素
        queue->rear = node;       // 设置当前元素为队尾
    }
    ++queue->size;
}
 
int QueuePop(struct Queue *queue, int *data)
{
    if (QueueEmpty(queue)) {
            return 0;
    }

    struct Link *tmp = queue->front; // 队列头删除节点
    *data = queue->front->data;
    queue->front = queue->front->next;
	printf("pop queue %d\n", *data);
    free(tmp);
    --queue->size;

    return 1;
}
 
void QueueDestroy(struct Queue* queue)
{
     struct Link *tmp;
     while(queue->front) { 
         tmp = queue->front;
         queue->front = queue->front->next;
         free(tmp);
     }
}

#define LENGTH 10000
int numSquares(int n) {
	int i, j,next = 0, curr = 0, size = 0, steps = 0, *visited;
	int *data = NULL;
    struct Queue *queue = NULL;
    
	queue = (struct Queue *)malloc(sizeof(struct Queue)); // 为根节点分配空间
	if (n == 0 || n == 1) {
		return n;
	}
	QueueInit(queue);
	visited = (int *)malloc(sizeof(int) * (LENGTH+1));
	data    = (int *)malloc(sizeof(int));
	memset(visited, 0, sizeof(int)*(LENGTH+1));

	QueuePush(queue, 0); // 根节点入队列,入队为队尾
	visited[0] = 1;      // 访问标记

	// 顺序遍历每一行,所以当节点差出现 0 时,此时一定是最短的路径
	while (!QueueEmpty(queue)) 
	{
		steps++; 
		size = queue->size;
		printf("------------steps is %d------------\n", steps);
		for (i = 0; i < size; i++) {
			QueuePop(queue, data);  // 队首元素出队
			curr = *data;           // 队首元素值
			printf("------curr is %d------\n", curr);
			for(j = 1; j*j <= n; j++) {
				next = curr+j*j; 
				printf("next is %d\n", next);
				if (next == n) {
					printf("!! bingo !! next == %d\n", n);
					return steps;
				} if (next > n) {
					break;
				} if (visited[next]) {
					continue;
				}
				visited[next] = 1;
				QueuePush(queue, next); // 节点入队
			}
		}
	}
	QueueDestroy(queue);
	return steps;
}

int main() {
	printf("\nresult is %d\n",numSquares(10));
	return 0;
}

解题思路::求解 10 的完全平方数为例,利用图的BFS遍历(之前我们学习过BFS是利用队列),即按层次进行遍历,遍历值不超过 n 的平方根(j*j < n),如下图所示,所以依次进队列的是 0,然后0出队列,进 1->4->9,出队列1,然后入队 2->5->10,10 满足题意退出(图中多画了10 右面的情况是为了说明,如果出现之前出现过的值,则直接返回结果,这一小技巧,避免BFS遍历已访问的元素,如下图中黑色的点)
在这里插入图片描述
如果借助打印,结果将如下所示:
在这里插入图片描述

发布了19 篇原创文章 · 获赞 32 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/wangwangmoon_light/article/details/104329159