无序数组及其子序列的相关问题研究
算法中以數(shù)組為研究對(duì)象的問(wèn)題是非常常見(jiàn)的. 除了排序大家經(jīng)常會(huì)遇到之外, 數(shù)組的子序列問(wèn)題也是其中的一大分類(lèi). 今天我就對(duì)自己經(jīng)常遇到的無(wú)序數(shù)組的子序列相關(guān)問(wèn)題在這里總結(jié)一下.
?
前置條件: 給定無(wú)序數(shù)組. 以下所以的問(wèn)題均以此為前置條件. 例如無(wú)序數(shù)組nums = [2, 1, 3].
?
問(wèn)題1:
求子序列的個(gè)數(shù). 例如前置無(wú)序數(shù)組的子序列個(gè)數(shù)為8, 分別為[], [2], [2, 1], [1], [2, 1, 3], [1, 3], [2, 3], [3].
分析:?
這個(gè)問(wèn)題應(yīng)該非常好理解. 對(duì)于它的子序列sub而言, 數(shù)組元素nums[i], 它要么存在于sub中, 要么不存在于sub中, 只有這兩種可能. 所以, 元素nums[i]能構(gòu)建的子序列個(gè)數(shù)為count(nums[i]) = 2. 因此, 對(duì)于數(shù)組nums的所有子序列的個(gè)數(shù)就為count(nums[0]) * count(nums[1]) * ... * count(nums[n-1]) = 2 * 2 * ... * 2 = 2^n(2的n次冪).?
所以, 對(duì)于長(zhǎng)度為n的無(wú)序數(shù)組, 它的所有子序列的個(gè)數(shù)為 2^n.
?
問(wèn)題2:
獲取nums的所有子序列.?例如前置無(wú)序數(shù)組的所有子序列為[], [2], [2, 1], [1], [2, 1, 3], [1, 3], [2, 3], [3].
分析:
首先, 我們按照問(wèn)題1的思路, "對(duì)于它的子序列sub而言, 數(shù)組元素nums[i], 它要么存在于sub中, 要么不存在于sub中, 只有這兩種可能", 我們可以創(chuàng)建一個(gè)只包含了0和1的長(zhǎng)度為n的數(shù)組, 則這個(gè)二進(jìn)制數(shù)組可以表示的10進(jìn)制數(shù)字的范圍恰好為[0, 2^n - 1]. 這個(gè)思路可以用下面這個(gè)表格表示如下(利用前置條件中給定的數(shù)組nums):
| binary\nums | 2 | 1 | 3 | subsequences |
| 0 | 0 | 0 | 0 | [] |
| 1 | 0 | 0 | 1 | [3] |
| 2 | 0 | 1 | 0 | [1] |
| 3 | 0 | 1 | 1 | [1, 3] |
| ... | ... | ... | ... | ... |
所以, 我們可以遍歷一下范圍[0, 2^n - 1], 然后將10進(jìn)制變量k轉(zhuǎn)化為二進(jìn)制數(shù)組, 然后利用二進(jìn)制數(shù)組中1的個(gè)數(shù)和位置, 構(gòu)建子序列.
這里提供一下上述思路的Java代碼如下:?
1 public List<List<Integer>> allSubsequences(int[] nums){ 2 if (nums == null){ 3 return null; 4 } 5 int max = Math.pow(2, nums.length); 6 List<List<Integer>> result = new ArrayList<>(); 7 for (int k = 0; k < max; k++){ 8 List<Integer> sub = new ArrayList<>(); 9 String binary = Integer.toBinaryString(k); 10 for(int i = binary.length() - 1; i >= 0; i--){ 11 if (binary.charAt(i) == '1'){ 12 sub.add(nums[nums.length - i - 1]); 13 } 14 } 15 result.add(sub); 16 } 17 return result; 18 }
?
與此同時(shí), 我們也可以利用動(dòng)態(tài)規(guī)劃的思想來(lái)解決這個(gè)問(wèn)題.
對(duì)于元素nums[i], 我們將它的所有子序列表示為subs(i). 那么對(duì)于nums[i-1]和nums[i], 則存在這些一個(gè)關(guān)系:
subs(i) = [nums[i], (sub + nums[i])], 其中滿足限制條件 sub in subs(i - 1).?
上述表達(dá)式想要表達(dá)的意思是: subs(i)生成的所有子序列, 由nums[i]和subs(i - 1)生成的所有子序列末尾加上nums[i]組成.
由此, 依據(jù)這種思路, 即利用動(dòng)態(tài)規(guī)劃思想生成所有子序列, 可以利用如下java代碼實(shí)現(xiàn):
1 public List<List<Integer>> allSubsequences(int[] nums){ 2 if (nums == null){ 3 return null; 4 } 5 List<List<Integer>> result = new ArrayList<>(); 6 result.add(new ArrayList<>());//add empty subsequence 7 for(int num : nums){ 8 List<List<Integer>> tmp = new ArrayList<>(result); 9 for(List<Integer> list : tmp){ 10 list.add(num); 11 } 12 result.addAll(tmp); 13 } 14 return result; 15 }
?
問(wèn)題3:
求所有遞增子序列的個(gè)數(shù).?例如前置無(wú)序數(shù)組的遞增子序列個(gè)數(shù)為5, 分別為[2], [1], [1, 3], [2, 3], [3].
分析:?
我們假設(shè)count(i)表示以nums[i]結(jié)尾的遞增子序列個(gè)數(shù). 則對(duì)于前置無(wú)序數(shù)組nums而言, 它的所有遞增子序列的個(gè)數(shù), 就是以nums[i]結(jié)尾的遞增子序列的和, 表示為sum(count(i))(0 < i < n - 1).
理解了以上假設(shè), 那么我們可以發(fā)現(xiàn)以下規(guī)律:?
count(0) = 1;
count(1) = 1; (nums[0] > nums[1])
count(2) = 1 + count(0) + count(1) (nums[0] < nums[2], nums[1] < nums[2])
? ? ? ? ? ? ?= 1 + 1 + 1 = 3;
所以, nums的所有遞增子序列個(gè)數(shù)就是count = count(0) + count(1) + count(2) = 1 + 1 + 3 = 5;
因而, 我的思路是: 建立一個(gè)數(shù)組counts = new int[nums.length + 1]用于保存以nums[i]結(jié)尾的遞增子序列的個(gè)數(shù), 即counts[i] = count(i). 而counts[nums.length]則用于累積counts[i], 表示整個(gè)序列的遞增子序列的個(gè)數(shù).
上述思路的Java實(shí)現(xiàn)如下:?
1 public int countIncreasingSubsequences(int[] nums){ 2 if (nums == null){ 3 return -1; 4 } 5 int[] counts = new int[nums.length + 1]; 6 for(int i = 0; i < nums.length; i++){ 7 counts[i] = 1;//單元素遞增序列計(jì)數(shù) 8 for(int j = 0; j < i; j++){ 9 if(nums[i] > nums[j]){ 10 counts[i] += counts[j]; 11 } 12 } 13 counts[nums.length] += counts[i]; 14 } 15 return counts[nums.length]; 16 }
?
問(wèn)題4:
求它的所有遞增子序列.?例如前置無(wú)序數(shù)組的所有遞增子序列為[2], [1], [1, 3], [2, 3], [3].
分析:
需要利用動(dòng)態(tài)規(guī)劃思想來(lái)分析這道題目. 其實(shí), 大體思路跟求它的所有子序列相同, 只不過(guò)是本問(wèn)題要求子序列是遞增的, 所以, 就利用遞增來(lái)修改求所有子序列的邏輯.
因而, 對(duì)于元素nums[i], 我們將它的所有子序列表示為subs(i). 那么對(duì)于nums[i-1]和nums[i], 則存在這些一個(gè)關(guān)系:
subs(i) = [nums[i], (sub + nums[i])], 其中滿足限制條件 sub in subs(i - 1) & sub.lastElement < nums[i].?
上述表達(dá)式想要表達(dá)的意思是: subs(i)生成的所有遞增子序列, 由nums[i]和subs(i - 1)生成的所有末尾元素小于nums[i]的遞增子序列末尾加上nums[i]組成.
由此, 依據(jù)這種思路, 即利用動(dòng)態(tài)規(guī)劃思想生成所有遞增子序列, 可以利用如下java代碼實(shí)現(xiàn):
1 public List<List<Integer>> allIncreasingSubsequences(int[] nums){ 2 if (nums == null){ 3 return null; 4 } 5 List<List<Integer>> result = new ArrayList<>(); 6 for(int num : nums){ 7 List<List<Integer>> tmp = new ArrayList<>(); 8 List<Integer> firstList = new ArrayList<>(); 9 firstList.add(num); 10 tmp.add(firstList); 11 for(List<Integer> list : result){ 12 if(list.get(list.size() - 1) < num){ 13 List<Integer> newList = new ArrayList<>(list); 14 newList.add(num); 15 tmp.add(newList); 16 } 17 } 18 } 19 return result; 20 }
?
最后, 關(guān)于遞減子序列的問(wèn)題, 原理跟遞增子序列問(wèn)題是一樣的, 這里就不再贅述, 有興趣的同學(xué), 可以自己手動(dòng)寫(xiě)一下.
轉(zhuǎn)載于:https://www.cnblogs.com/littlepanpc/p/7954896.html
總結(jié)
以上是生活随笔為你收集整理的无序数组及其子序列的相关问题研究的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 黄山风景区门票老年人优惠多少
- 下一篇: JAVA-初步认识-第十一章-objec