C算法-贪心/回溯/剪枝

leetcode698题,划分为k个相等的子集。主要是found函数的精妙的回退grp-=nums[start]
leetcode40题,两数相加II。在判断OK的地方保存结果
leetcode322题,零钱兑换。有个妙处是amount/coins[i],一下转换了思路。
leetcode93题,复原IP地址。在判断OK的地方保存结果,另外也要处理回退。其实对一个char处理回退,有个更好的方式是记录上次的end,tmpret[end] = '\0’

主要思路介绍:
1、快排对数据进行整理(贪心),调用一个函数dfs()
2、dfs的结构:退出判断,剪枝判断,for循环, dfs()递归
3、dfs的参数要求:包含有收敛条件相关的参数,包含start参数
4、退出判断:if start == xxx结束
5、剪枝判断:xxx return掉
6、for循环,有时候在这里也进行剪枝。
7、操作+dfs+回退操作
在这里插入图片描述

摘自百科:

回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。 用回溯算法解决问题的一般步骤:
1、 针对所给问题,定义问题的解空间,它至少包含问题的一个(最优)解。
2 、确定易于搜索的解空间结构,使得能用回溯法方便地搜索整个解空间 。
3 、以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索。
回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。

698题目要求:对一个数组 [4, 3, 2, 3, 5, 2, 1]划分成4组,使得每组的和都等于5,是否存在。
因此需要个grpSum来记录每组当前和是多少
函数解释:
1、只有start是变量,去试遍每个组,target是收敛条件,但是这道题目不需要变化。
2、如果满足要求,对start+1递归,即可实现对arr中的每个元素的遍历
3、回退操作:如果当前路径不可以找到最后答案,那么对grpSum进行回退操作

bool dfs(int *nums, int numsSize, int start, int grpnum, int target)
{
    
    
    if (start == numsSize) {
    
    
        return true;
    }
    int i;
    for (i = 0; i < grpnum; i++) {
    
    
        if (grp[i] + nums[start] > target) {
    
    
            continue;
        }
        grp[i] += nums[start];

        bool a = dfs(nums, numsSize, start + 1, grpnum, target);
        if (a == true) {
    
    
            return true;
        }
        grp[i] -= nums[start];
    }
    return false;
}

40题目要求:对一个数组[10,1,2,7,6,1,5],记录所有可以等于8的组合,并返回出来所有可能的结果。
函数解释:
1、start是起始地址,target是收敛条件的参数。选中start以后,去尝试后面start+1。存储某类结果,嘻嘻,已经用全局变量g_len替换了,因为想统一格式
2、选中的start如果上次选过,就不去尝试了(去重)
3、如果当前值小于目标值,就给g_tmp加上当前元素
4、如果当前值等于目标值,target == 0,就给g_ret[g_count]填上g_tmp
5、同样对g_tmp有恢复操作

void dfs(int* candidates, int candidatesSize, int start, int target) {
    
    
    if (0 == target) {
    
          //满足条件,直接输出。
        g_ret[g_count] = (int*)malloc(sizeof(int)*g_len);
        if (g_ret[g_count] == NULL) {
    
    
            return;
        }
        memcpy(g_ret[g_count], g_tmp, g_len * sizeof(int));
        g_col[g_count] = g_len;
        g_count++;
    }
	if (start == candidatesSize) {
    
    
		return;
	}
	int i, curr, pre;
	pre = 0;
	for (i = start; i < candidatesSize; i++) {
    
    
		curr = candidates[i];
		if (pre != 0 && curr == pre) {
    
     //去重
			continue;
		}
		pre = curr;
		if (candidates[i] > target) {
    
     //当前元素不满足条件
			continue;
		}
		g_tmp[g_len++] = candidates[i];
		dfs(candidates, candidatesSize, i + 1, target - candidates[i]);
		g_len--;
	}
	return;
}

322题目要求:对一个币[1,2,5],目标是11,如何获取最少硬币数,答案是5+5+1
函数解释:
1、start是起始索引,amount是收敛条件的参数;因为是用的除法,如果选中合适的start以后,可以直接尝试start+1了,保证继续执行。
2、如果当前次数大于等于mincount了,就不需要尝试了(剪枝),一定要break,不然会超时
3、如果当前已经满足要求了,就看是否当前g_count比最小值小,进行替换
4、同样对g_count有回退操作

int g_count;
int g_mincount;

void dfs(int* coins, int coinsSize, int start, int amount) {
    
    
	//printf("%d %d %d %d\n", start, amount, g_mincount, g_count);
    if (amount == 0) {
    
    
		if (g_count < g_mincount){
    
    
			g_mincount = g_count;
		}
		return;
	}
	if (start == coinsSize) {
    
    
		return;
	}
    int k;
	for (k = amount / coins[start]; k >= 0; k-- ){
    
    
        if (k + g_count >= g_mincount) {
    
    
            break;
        }
        g_count += k;
		dfs(coins, coinsSize, start + 1, amount - k * coins[start]);
        g_count -= k;
	}
	return;
}

93题目要求,给定字符串: “25525511135”,找出可能的IP [“255.255.11.135”, “255.255.111.35”]。
函数解释:
1、变量是start和count,count用来存储当前剩余的ip数字个数,如果当前start ,end符合要求,那么可以考虑剩下的count–;
2、for循环中尝试[start,start] - [start,start+2]的所有可能性,回溯
3、考虑剩余长度和count的关系,不能太多也不能太少,剪枝
4、保存结果的回退处理,g_tmpret[len] = '\0';
5、如果满足结果,直接申请空间然后输出

void dfs(char *s, int length, int start,  int count, char **ret)
{
    
    
    if (count == 0 && start == length){
    
    
        ret[g_count] = (char*)malloc(sizeof(char)*(strlen(g_tmpret) + 1));
        memcpy(ret[g_count], g_tmpret, strlen(g_tmpret) + 1);
        g_count++;
    }
	int end, numlen, len;
    char tmp[4];
	for (end = start; end <= start + 2 && end < length; end++) {
    
    
		if ((length - end - 1) > 3 * (count - 1)) {
    
    
			continue;
		} else if ((length - end - 1) < (count - 1)) {
    
    
			continue;
		}
		numlen = end - start + 1;
		memset(tmp, 0, 4);
		memcpy(tmp, s+start, numlen);
        if (Chk255(tmp, numlen) == false) {
    
    
            continue;
        }
        len = strlen(g_tmpret);
        strcat(g_tmpret, tmp);
		if (count != 1) {
    
    
			strcat(g_tmpret, ".");
		}
		dfs(s, length, end + 1,  count - 1, ret);	
		g_tmpret[len] = '\0';	
	}
	return;
}

附40题目答案

#define MAXLEN 1200
int g_tmp[MAXLEN];
int *g_col = NULL;
int g_len;
int **g_ret = NULL;
int g_count;
int Comp(const void *a, const void *b)
{
    
    
	return *(int*)b - *(int*)a;
}
void dfs(int* candidates, int candidatesSize, int start, int target) {
    
    
    if (0 == target) {
    
          //满足条件,直接输出。
        g_ret[g_count] = (int*)malloc(sizeof(int)*g_len);
        if (g_ret[g_count] == NULL) {
    
    
            return;
        }
        memcpy(g_ret[g_count], g_tmp, g_len * sizeof(int));
        g_col[g_count] = g_len;
        g_count++;
    }
	if (start == candidatesSize) {
    
    
		return;
	}
	int i, curr, pre;
	pre = 0;
	for (i = start; i < candidatesSize; i++) {
    
    
		curr = candidates[i];
		if (pre != 0 && curr == pre) {
    
     //去重
			continue;
		}
		pre = curr;
		if (candidates[i] > target) {
    
     //当前元素不满足条件
			continue;
		}
		g_tmp[g_len++] = candidates[i];
		dfs(candidates, candidatesSize, i + 1, target - candidates[i]);
		g_len--;
	}
	return;
}
int** combinationSum2(int* candidates, int candidatesSize, int target, int* returnSize, int** returnColumnSizes) {
    
    
	if (candidatesSize == 0) {
    
    
		*returnSize = 0;
		return NULL;
	}
    
	qsort(candidates, candidatesSize, sizeof(int), Comp);
	memset(g_tmp, 0, MAXLEN * sizeof(int));
    g_ret = NULL;
    g_col = NULL;
	g_count = 0;
	g_len = 0;
	g_ret = (int**)malloc(sizeof(int*) * MAXLEN);
    if (g_ret == NULL) {
    
    
        *returnSize = 0;
		return NULL;
    }
    g_col = (int*)malloc(sizeof(int) * MAXLEN);
    if (g_col == NULL) {
    
    
        *returnSize = 0;
		return NULL;
    }
	dfs(candidates, candidatesSize, 0, target);
	*returnSize = g_count;
	*returnColumnSizes = g_col;
	return g_ret;
}

698题目答案

int comp(const void *a, const void *b) {
    
    
	return *(int*)b - *(int*)a;
}

bool found(int* nums, int numsSize, int start, int grp, int target, int* grpSum) {
    
    
	int j = 0;
	if (start == numsSize) {
    
    
		return true;
	}
	for (j = 0; j < grp; j++) {
    
    
		if (grpSum[j] + nums[start] <= target) {
    
    
			grpSum[j] += nums[start];
			if (found(nums, numsSize, start + 1, grp, target, grpSum)) {
    
    
				return true;
			}
			grpSum[j] -= nums[start];
		}
	}
	return false;

}

bool canPartitionKSubsets(int* nums, int numsSize, int k) {
    
    
	int sum, average, i, count;
	sum = 0;
	int grpSum[16] = {
    
     0 };
	for (i = 0; i < numsSize; i++) {
    
    
		sum = sum + nums[i];
	}
	if (sum % k != 0) return 0;
	average = sum / k;

	qsort(nums, numsSize, sizeof(int), comp);
	return found(nums, numsSize, 0, k, average, grpSum);

}

322答案

int comp(const void *a, const void *b)
{
    
    
	return *(int*)b - *(int*)a;
}

int g_count;
int g_mincount;

void dfs(int* coins, int coinsSize, int start, int amount) {
    
    
	//printf("%d %d %d %d\n", start, amount, g_mincount, g_count);
    if (amount == 0) {
    
    
		if (g_count < g_mincount){
    
    
			g_mincount = g_count;
		}
		return;
	}
	if (start == coinsSize) {
    
    
		return;
	}
    int k;
	for (k = amount / coins[start]; k >= 0; k-- ){
    
    
        if (k + g_count >= g_mincount) {
    
    
            break;
        }
        g_count += k;
		dfs(coins, coinsSize, start + 1, amount - k * coins[start]);
        g_count -= k;
	}
	return;
}

int coinChange(int* coins, int coinsSize, int amount) 
{
    
    
	qsort(coins, coinsSize,sizeof(int), comp);
	g_mincount = 0x7fffffff;
    g_count = 0;
	dfs(coins, coinsSize, 0, amount);

    if (g_mincount == 0x7fffffff){
    
    
        return -1;
    }
	return g_mincount;
}

93答案

char g_tmpret[16];
int g_count;
#define MAXLEN 103

bool Chk255 (char *tmp, int numlen)
{
    
    
    if (numlen == 3) {
    
    
        if (tmp[0] > '2' || tmp[0] == '0') {
    
    
            return false;
        }
        if (tmp[0] == '2' && tmp[1] > '5') {
    
    
            return false;
        }else if (tmp[0] == '2' && tmp[1] == '5' && tmp[2] > '5') {
    
    
            return false;
        }
    }
    if (numlen == 2) {
    
    
        if (tmp[0] == '0') {
    
    
            return false;
        }
    }
    return true;
}

void dfs(char *s, int length, int start,  int count, char **ret)
{
    
    
    if (count == 0 && start == length){
    
    
        ret[g_count] = (char*)malloc(sizeof(char)*(strlen(g_tmpret) + 1));
        memcpy(ret[g_count], g_tmpret, strlen(g_tmpret) + 1);
        g_count++;
    }
	int end, numlen, len;
    char tmp[4];
	for (end = start; end <= start + 2 && end < length; end++) {
    
    
		if ((length - end - 1) > 3 * (count - 1)) {
    
    
			continue;
		} else if ((length - end - 1) < (count - 1)) {
    
    
			continue;
		}
		numlen = end - start + 1;
		memset(tmp, 0, 4);
		memcpy(tmp, s+start, numlen);
        if (Chk255(tmp, numlen) == false) {
    
    
            continue;
        }
        len = strlen(g_tmpret);
        strcat(g_tmpret, tmp);
		if (count != 1) {
    
    
			strcat(g_tmpret, ".");
		}
		dfs(s, length, end + 1,  count - 1, ret);	
		g_tmpret[len] = '\0';	
	}
	return;
}

char ** restoreIpAddresses(char * s, int* returnSize) {
    
    
	if (s == NULL) {
    
    
		*returnSize = 0;
		return NULL;
	}
	char ** ret = (char **)malloc(sizeof(char *) * MAXLEN);
	g_count = 0;
	memset(g_tmpret, 0, 16);
	int count = 4;
	int length = strlen(s);
	dfs(s, length, 0,  count, ret);
	*returnSize = g_count;
	return ret;
}

猜你喜欢

转载自blog.csdn.net/weixin_45554139/article/details/104672443