Sublist (หรือ Subsequence) คือลำดับย่อยที่สร้างจากการเลือกสมาชิกจาก List ต้นฉบับโดย **รักษาลำดับเดิม** สำหรับ String "xyz" จะได้ Sublists: x, y, z, xy, xz, yz, xyz (รวม Empty String ถ้านับ)
อัลกอริทึม: Generate All Subsequences
สำหรับ String ความยาว n จะมี Subsequences ทั้งหมด 2^n แบบ (รวม Empty String)
ตัวอย่างโค้ด (แก้ไขจากต้นฉบับให้ทำงานถูกต้อง)
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo {
class MyApplication {
static void Main(string[] args) {
string str = "xyz";
// ใช้ List แทน List แบบ Raw
var list = new List();
// Generate all non-empty subsequences
for (int i = 0; i < str.Length; i++) {
// เพิ่มตัวอักษรเดี่ยว
list.Add(str[i].ToString());
// สร้าง Subsequences ใหม่จากที่มีอยู่
var newList = new List();
for (int j = 0; j < list.Count - 1; j++) { // -1 เพื่อไม่เอาตัวที่เพิ่ง Add
string combined = list[j] + str[i];
newList.Add(combined);
}
list.AddRange(newList);
}
list.Sort(); // เรียงลำดับ
Console.WriteLine(string.Join(Environment.NewLine, list));
}
}
}
ผลลัพธ์
x
xy
xyz
xz
y
yz
z
วิธีที่ดีกว่า: ใช้ Bit Manipulation
เหมาะกับ n ≤ 30 (2^30 ≈ 1 billion)
public static List GetAllSubsequences(string str) {
var result = new List();
int n = str.Length;
int total = 1 << n; // 2^n
for (int mask = 1; mask < total; mask++) { // เริ่ม 1 = ข้าม Empty String
var chars = new char[n];
int idx = 0;
for (int i = 0; i < n; i++) {
if ((mask & (1 << i)) != 0) {
chars[idx++] = str[i];
}
}
result.Add(new string(chars, 0, idx));
}
result.Sort();
return result;
}
วิธี Recursive (Backtracking)
public static void GenerateSubsequences(string str, int index, string current, List result) {
if (index == str.Length) {
if (!string.IsNullOrEmpty(current))
result.Add(current);
return;
}
// ไม่เอาตัวนี้
GenerateSubsequences(str, index + 1, current, result);
// เอาตัวนี้
GenerateSubsequences(str, index + 1, current + str[index], result);
}
// ใช้งาน
var result = new List();
GenerateSubsequences("xyz", 0, "", result);
result.Sort();
สำหรับ List<T> ทั่วไป (ไม่ใช่ String)
public static List> GetAllSublists(List source) {
var result = new List>();
int n = source.Count;
int total = 1 << n;
for (int mask = 1; mask < total; mask++) {
var sublist = new List();
for (int i = 0; i < n; i++) {
if ((mask & (1 << i)) != 0) {
sublist.Add(source[i]);
}
}
result.Add(sublist);
}
return result;
}
// ใช้งาน
var numbers = new List { 1, 2, 3 };
var sublists = GetAllSublists(numbers);
// [[1], [2], [1,2], [3], [1,3], [2,3], [1,2,3]]
Complexity Analysis
| Method | Time | Space | Note |
|---|---|---|---|
| Iterative (Bit Mask) | O(n × 2^n) | O(n × 2^n) | Fast, No Recursion |
| Recursive Backtracking | O(n × 2^n) | O(n) Stack + Output | Clean, Easy to Understand |
| Original (Flawed) | O(n × 2^n) | O(n × 2^n) | Logic Error ในต้นฉบับ |
⚠️ หมายเหตุ
โค้ดต้นฉบับมี Logic Error ที่ list.Add(str[i - 1].ToString()) และ Loop เริ่มจาก i=1 ทำให้พลาดตัวแรกและตัวสุดท้าย โค้ดข้างบนแก้ไขแล้ว