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;
}