字符串组合算法

65 篇文章 1 订阅
36 篇文章 2 订阅

全组合

例如给定字符串“abc”,全组合意思从中去0个元素,1个元素,一直到n个元素,介绍二进制做法。以字符串“abc”为例:
  • 000 <---> NULL
  • 001 <---> c
  • 010 <---> b
  • 011 <---> bc
  • 100 <---> a
  • 101 <---> ac
  • 110 <---> ab
  • 111 <---> abc

思路出来了,代码也比较好写,分享一下我的代码:

/**
 * Write a method that returns all subsets of a set
 */

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

/**
 * 通过0到2^-1来标识子集
 *
 * T = (n * 2^n)
 *
 */
void getSubset(char *str, int len)
{
	int i, max, index, j;

	max = 1 << len;

	for (i = 1; i < max; i ++) {
		j = i;
		index = 0;

		while (j) {
			if (j & 1) {
				printf("%c", str[index]);
			}
			j >>= 1;
			index ++;
		}
		printf("\n");
	}
}

int main(void)
{
	char str[1000];

	while (scanf("%s", str) != EOF) {
		getSubset(str, strlen(str));

	}

	return 0;
}


从n中选m个数


这里分为两种方法:递归和回溯

递归

递归思路如下,从n个数中取出m个数,可以分解为以下两步:
  1. 从n个数中选取编号最大的数,然后在剩下的n-1个数中选取m-1个数。直到从n-(m-1)中选取一个数为止
  2. 从n个数中选取次小的数,重复1的操作

代码如下:

/**
 * 递归法解决组合问题
 */
void combine(int *arr, int n, int m, int *tmp, const int M)
{
	int i, j;

	for (i = n; i >= m; i --) {
		tmp[m] = i;
		if (m == 0) {	// 选出m个数
			for (j = 0; j < M; j ++) {
				printf("%d ", arr[tmp[j]]);
			}
			printf("\n");
		} else {
			combine(arr, i - 1, m - 1, tmp, M);
		}
 	}
}

DFS

其实考虑到用dfs,这道题目就简单很多,dfs的回溯条件就是临时数组的大小==k即可,同时附加一道LeetCode上的题目,用dfs思路ac

题目
Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.

For example,
If n = 4 and k = 2, a solution is:



ac代码
public class Solution {
    public static ArrayList<ArrayList<Integer>> combine(int n, int k) {
        ArrayList<ArrayList<Integer>> rs = new ArrayList<ArrayList<Integer>>();
        ArrayList<Integer> list = new ArrayList<Integer>();
        
        dfs(1, k, n, list, rs);
        
        return rs;
    }
    
    public static void dfs(int pos, int k, int n, ArrayList<Integer> list, ArrayList<ArrayList<Integer>> rs) {
        if (list.size() == k) {
            rs.add(new ArrayList<Integer>(list));
        }
        
        for (int i = pos; i <= n; i ++) {
            list.add(i);
            dfs(i + 1, k, n, list, rs);
            list.remove(list.size() - 1);
        }
    }
}





评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值