题目: Combinations

1-n个数字中找k个数字的所有不同组合。

思路:从1-k开始,每次从k开始,让最后面的元素加1,超过了,就让前面一个元素加1,后面一个元素变为前面一个元素的值加1.

循环知道所有元素都没有超过,则是一种不同的情况。

例如:n = 6,k = 4;

1234->1235->1236->1245->1246->1256->1345->1346->1356->1456

->2345->...->3456

package com.example.medium;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class Combinations {
    public List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> list = new LinkedList<>();
        int indexs[] = new int[k];
        int j = 0;
        for(int i = 0;i < k;i++){
            indexs[i] = i;
        }
        while(indexs[0] <= n - k){
            List<Integer> item = new ArrayList<Integer>(k);
            for(int i = 0;i <k;i++){//添加当前的k个元素
                item.add(i, indexs[i] + 1);
            }
                list.add(item);
                j = k - 1;
                indexs[j]++;//最后一个元素加一
                while(indexs[j] >= n - k + j + 1){//超过了n则倒数第二个元素加一,然后判断是否超过n,如此循环
                    j--;
                    if(j < 0)break;
                    indexs[j]++;
                }
                for(;j >= 0 && j < k - 1;j++)
                    indexs[j + 1] = indexs[j] + 1;
        }
        return list;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        List<List<Integer>> list = new Combinations().combine(17, 5);
        Iterator<List<Integer>> iterator = list.iterator();
        while(iterator.hasNext()){
            List<Integer> item = iterator.next();
            for(int i = 0;i < item.size();i++)
                System.out.print(item.get(i) + " ");
            System.out.println();
        }

    }

}

 题目:Subsets

找到给定数组的所有子集;数组中每个元素都不同

思路:

和上面一样,不过这次没有固定的k值。

让k从0开始一直加到n(数组长度),然后按照上面的方法找到所有子集。

package com.example.medium;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class Subsets {
    public List<List<Integer>> subsets(int[] nums) {
      List<List<Integer>> list = new LinkedList<>();
      int index[] = new int[nums.length];//存储元素下标
      int i = 0,k = 0;
      while (i <= nums.length) {
                List<Integer> item = new ArrayList<>(i);
                for (int j = 0; j < i; j++) {//添加子集
                    item.add(j, nums[index[j]]);
                }
                list.add(item);
                k = i - 1;//k减一
                if(k < 0){//元素个数为i的子集找完了
                    i++;
                    continue;
                }
                index[k]++;//最后一个元素的下标加一
                while(index[k] > nums.length - i + k){
                    k--;//
                    if(k < 0)break;
                    index[k]++;
                }
                if(k < 0){//元素个数为i的子集找完了
                    i++;
                    if(i > nums.length)break;
                    for (int j = 0; j < i; j++) {//当i增加时,重新初始化
                        index[j] = j;
                    }
                }else{
                    for(;k < i - 1;k++)
                        index[k + 1] = index[k] + 1;
                }
            }
      return list;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        List<List<Integer>> list = new Subsets().subsets(new int[]{1,2,3,4,5,6});
        Iterator<List<Integer>> iterator = list.iterator();
        while(iterator.hasNext()){
            List<Integer> item = iterator.next();
            for(int i = 0;i < item.size();i++)
                System.out.print(item.get(i) + " ");
            System.out.println();
        }

    }

}

题目:SubsetsII

找到给定数组的所有子集;数组中有相同元素。

思路:

和上面的相同,但是在查找前先排序,然后每次跳过元素之相同的元素。

package com.example.medium;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
 * Given a collection of integers that might contain duplicates, nums, return all possible subsets.
 * 
 * Note: The solution set must not contain duplicate subsets.
 * 
 * For example,
 * If nums = [1,2,2], a solution is:
 * 
 * [
 *   [2],
 *   [1],
 *   [1,2,2],
 *   [2,2],
 *   [1,2],
 *   []
 * ]
 * @author qfp
 *
 */
public class SubSets2 {
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>> list = new LinkedList<List<Integer>>();
        Arrays.sort(nums);
        int[] index = new int[nums.length];//记录当前情况的下标
        int i = 0,k = 0;//i表示子集中元素的个数
        while(i <= nums.length){
            List<Integer> item = new ArrayList<Integer>(i);
            for (int j = 0; j < i; j++) {//将当前情况添加进去
                item.add(j, nums[index[j]]);
            }
            list.add(item);
            k = i - 1;//更新当前子集个数为i时,新的可能的子集
            if(k < 0){//当i = 0时,只有一个空集
                i++;
                continue;
            }
            //先更新id最大的元素,去重
            while(index[k] < nums.length - 1 && nums[index[k]] == nums[index[k] + 1])index[k]++;
            index[k]++;
            while(index[k] > nums.length - i + k){
                k--;//
                if(k < 0)break;//k小于0时,表示个数为i的子集全部找到了
                while(index[k] < nums.length - 1 && nums[index[k]] == nums[index[k] + 1])index[k]++;
                index[k]++;
            }
            if(k < 0){
                i++;
                if(i > nums.length)break;
                for (int j = 0; j < i; j++) {//当i增加时,重新初始化
                    index[j] = j;
                }
            }else{
                for(;k < i - 1;k++)
                    index[k + 1] = index[k] + 1;
            }
        }
        return list;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        List<List<Integer>> list = new SubSets2().subsetsWithDup(new int[]{1,2,2,1,1});
        Iterator<List<Integer>> iterator = list.iterator();
        while(iterator.hasNext()){
            List<Integer> item = iterator.next();
            for(int i = 0;i < item.size();i++)
                System.out.print(item.get(i) + " ");
            System.out.println();
        }

    }

}