leetcode 279. 完全平方数 bfs广度优先解法 图解 c代码

如题:

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

示例 1:
输入: n = 12
输出: 3 
解释: 12 = 4 + 4 + 4.

示例 2:
输入: n = 13
输出: 2
解释: 13 = 4 + 9.

这道题和leetcode 752. 打开转盘锁类似,都可以使用广度优先搜索来求解。大体思路都是根据遍历当前节点的子节点,寻找目标解的过程,类似题目做多了,就比较容易了。

这道题可以看作从根节点0出发,往下搜索子节点,找到匹配则返回深度即可,相当于最短路径,当然是广度优先搜索BFS。
每层节点的子节点分别为父节点加上(1, 4, 9, 16....(i^2 < n) )。使用队列存储节点,每次遍历前先获取当层节点数,即队列长度。然后依次遍历该节点子节点,如果长度符合则返回,不符合且是第一次访问,则添加到队列中去,如果已经访问过,则不需要添加。需要额外的哈希数组,用来存储访问过的元素,队列和哈希数组总共需要额外的2N的空间。bfs搜索方法协同队列的使用代码框架比较固定,往往可以共用一套代码。下面是本题的图示:

leetcode 279. 完全平方数  bfs广度优先解法  图解  c代码

c语言代码如下,前面部分代码是关于队列实现的,可以略过不看,仅看最后的bfs搜索部分即可。


/* BFS */

typedef struct {
    int length, max;
    int front, rear;
    int *sq;
} queue;

//创建队列
queue* queueCreate(int k) {
    queue* a;
    if (k < 0)
        return NULL;
    else
        a = (queue*) malloc(sizeof(queue));
    if (!a)
        return NULL;
    else
    {
        a->max = k+1;
        a->length = a->front = a->rear = 0;
        a->sq = (int *)malloc(sizeof(int) * (k+1));
        if (!a->sq)
        {
            free(a);
            return NULL;
        }
        return a;
    }    
}

//入队列
int enQueue(queue* obj, int value) {
    if (obj->length == (obj->max - 1))
        return 0;
    else
    {
        obj->sq[obj->rear] = value;
        obj->rear = (obj->rear + 1) % obj->max;
        obj->length++;
    }
        
    return 1;
}

//出队列
int deQueue(queue* obj) {
    int head;
    
    if (obj->front == obj->rear)
        return 0;
    else
    {
        head= obj->front;
        obj->front = (obj->front + 1) % obj->max;
        obj->length--;
        return obj->sq[head];
    }
}

//获取当前队列长度
int queueLength(queue *obj)
{
    return obj->length;
}

//判断队列是否为空
int isEmpty(queue* obj) {
     if (obj->front == obj->rear)
        return 1;
    else
        return 0;
}

//判断队列是否满
int isFull(queue* obj) {
    if (obj->length == obj->max - 1)
        return 1;
    else
        return 0;
}

//释放队列
void queueFree(queue* obj) {
    free(obj->sq);
    free(obj);
    return;
}


int numSquares(int n){
    int i,j,next, curr, size, steps = 0, *visited;
    queue *q;
    
    if (n == 0 || n == 1)
        return n;
    
    q = queueCreate(n + 1);
    visited = (int *)malloc(sizeof(int) * (n+1));
    for (i = 0; i <= n; i++)
        visited[i] = 0;
    
    enQueue(q, 0);
    visited[0] = 1;
    
    while(!isEmpty(q))
    {
        //深度递增
        steps++;
        size = queueLength(q);
        for (i = 0; i < size; i++)
        {
            //遍历子节点
            curr = deQueue(q);
            for (j = 1; j * j <= n; j++)
            {
                next = curr + j*j;
                if (next == n) return steps;
                if (next > n) break;
                if (visited[next]) continue;
                //加入到队列,以待访问其子节点
                visited[next] = 1;
                enQueue(q, next);
            }
        }
    }
    queueFree(q);
    free(visited);
    return steps;
}

 

上一篇:洛谷-1093 奖学金


下一篇:LeetCode 279. 完全平方数(Perfect Squares)