給定一列數(未排序)和一列目標值, 找出唯一的一個組合和等於目標值的組合, 數組中的數不能重複使用.
演算法思路: 使用遞迴.
對數組排序, 從小到大;
令i = 起始下標(初始為0), 對於每一個數,
如果它等於目標值, 則在緩衝結果中加入此數並將緩衝結果加入輸出隊列, 隨後在緩衝結果中刪除此數;
如果它小於目標值, 則在緩衝結果中加入此數並遞迴調用此演算法, 目標值更新為差值, 起始下標為i;
如果它大於目標值, 演算法返回.
對於2.2的理解: 如果這個數小於目標值, 由於演算法是迴圈遞迴, 那麼起始的下標必定不能小於i(否則出現重複情況)
代碼如下:
import java.util.Arrays;import java.util.Collections;import java.util.LinkedHashMap;import java.util.LinkedList;import java.util.List;import java.util.Map;/** * 將手續約作為一筆交易,如果拼湊不出來,則拆分剩餘明細中金額最大的那筆交易 * @author kenan.zhang * @date 2017-08-23 */public class Calc { public static void recursion(List<Integer> sourceList,LinkedList<Integer> tmpList,List<LinkedList<Integer>> resultList,Integer targetValue,int startIndex){ for (int i = startIndex; i < sourceList.size(); i++) { Integer currentValue = sourceList.get(i); if(currentValue <= targetValue){ if(currentValue.equals(targetValue)){ tmpList.add(currentValue); resultList.add(new LinkedList<Integer>(tmpList)); tmpList.remove(currentValue); break; }else if(currentValue < targetValue){ tmpList.add(currentValue); recursion(sourceList, tmpList, resultList, targetValue-currentValue, i+1); tmpList.remove(currentValue); //只取第一個合格資料群組 if(resultList.size() == 1){ //從來源資料列表中去掉已經使用過的資料 sourceList.removeAll(resultList.get(0)); break; } } }else{ break; } } } public static Map<Integer,LinkedHashMap<Integer,List<Integer>>> getResult(List<Integer> sourceList,List<Integer> targetValues){ Collections.sort(sourceList); Collections.sort(targetValues); int startIndex = 0; List<Integer> remainTargetValues = new LinkedList<Integer>(); Map<Integer,LinkedHashMap<Integer,List<Integer>>> resultMap = new LinkedHashMap<Integer,LinkedHashMap<Integer,List<Integer>>>(); for(int i=0;i<targetValues.size();i++){ Integer currentValue = targetValues.get(i); List<LinkedList<Integer>> resultList = new LinkedList<LinkedList<Integer>>(); LinkedList<Integer> tmpList = new LinkedList<Integer>(); recursion(sourceList, tmpList, resultList,currentValue, startIndex); if(resultList.size() == 0){ remainTargetValues.add(currentValue); resultMap.put(currentValue, null); }else{ LinkedHashMap<Integer,List<Integer>> res = new LinkedHashMap<Integer,List<Integer>>(); //為了區分該匯總交易是否通過某筆交易明細拆分拼湊而來:如果子map的key為Integer.MAX_VALUE,否則對應的是被拆分的交易明細 res.put(Integer.MAX_VALUE, resultList.get(0)); resultMap.put(currentValue, res); } } //對最大的一筆交易進行拆分 int lastIndex = sourceList.size()-1; Integer lastValue = sourceList.get(lastIndex); for(int i=0;i<remainTargetValues.size();i++){ Integer targetValue = remainTargetValues.get(i); List<Integer> myTmpList = new LinkedList<Integer>(); Integer gap = lastValue - sourceList.get(i); if(gap >= 0){ myTmpList.add(sourceList.get(i)); myTmpList.add(targetValue-sourceList.get(i)); Collections.sort(myTmpList); LinkedHashMap<Integer,List<Integer>> res = new LinkedHashMap<Integer,List<Integer>>(); //為了區分該匯總交易是否通過某筆交易明細拆分拼湊而來:如果子map的key為Integer.MAX_VALUE,否則對應的是被拆分的交易明細 res.put(lastValue, myTmpList); resultMap.put(targetValue, res); sourceList.set(lastIndex, gap); }else{ System.out.println(sourceList); for(int k=remainTargetValues.size()-1;k<sourceList.size();k++){ myTmpList.add(sourceList.get(k)); } myTmpList.add(lastValue); LinkedHashMap<Integer,List<Integer>> res = new LinkedHashMap<Integer,List<Integer>>(); //為了區分該匯總交易是否通過某筆交易明細拆分拼湊而來:如果子map的key為Integer.MAX_VALUE,否則對應的是被拆分的交易明細 res.put(lastValue, myTmpList); resultMap.put(targetValue, res); } } return resultMap; } //重載 public static Map<Integer,LinkedHashMap<Integer,List<Integer>>> getResult(Integer[] source,Integer[] target){ List<Integer> sourceList = new LinkedList<Integer>(); sourceList.addAll(Arrays.asList(source)); LinkedList<Integer> targetValues = new LinkedList<Integer>(Arrays.asList(target)); return getResult(sourceList, targetValues); } public static void main(String[] args) { Integer[] source = new Integer[]{69, 35, 29, 26, 18, 12, 46, 92, 96, 75, 58, 34, 110}; Integer[] target = new Integer[]{104,44,58,61,73,260,100}; Map<Integer,LinkedHashMap<Integer,List<Integer>>> resultMap = getResult(source, target); System.out.println("結果resultMap是:"+resultMap); List<Integer> sourceList = new LinkedList<Integer>(); sourceList.addAll(Arrays.asList(source)); LinkedList<Integer> targetValues = new LinkedList<Integer>(Arrays.asList(target)); Map<Integer,LinkedHashMap<Integer,List<Integer>>> resultMap2 = getResult(sourceList, targetValues); System.out.println("結果resultMap2是:"+resultMap2); }}
改進版:
import java.math.BigDecimal;import java.util.Collection;import java.util.Collections;import java.util.HashMap;import java.util.LinkedList;import java.util.List;import java.util.Map;/** * 將手續約作為一筆交易,如果拼湊不出來,則拆分剩餘明細中金額最大的那筆交易 * 該方案理論上可能存在需要拆分多筆交易的情況 * @author kenan.zhang * @date 2017-08-23 */public class Calculator2 { public static void recursion(List<Map<String,Object>> detailList,LinkedList<Map<String,Object>> tmpList,LinkedList<Object> resultList,Map<String,Object> targetSummary,int startIndex){ for (int i = startIndex; i < detailList.size(); i++) { Map<String,Object> currentDetail = detailList.get(i); BigDecimal summaryMoney = (BigDecimal) targetSummary.get("summaryMoney"); BigDecimal detailMoney = (BigDecimal) currentDetail.get("detailMoney"); if(detailMoney.compareTo(summaryMoney) != 1){ if(detailMoney.compareTo(summaryMoney) == 0){ tmpList.add(currentDetail); resultList.add(new LinkedList<Map<String,Object>>(tmpList)); tmpList.remove(currentDetail); resultList.add(targetSummary); //從來源資料列表中去掉已經使用過的資料 detailList.removeAll((Collection<?>) resultList.get(0)); break; }else if(detailMoney.compareTo(summaryMoney) == -1){ tmpList.add(currentDetail); targetSummary.put("summaryMoney", summaryMoney.subtract(detailMoney)); recursion(detailList, tmpList, resultList, targetSummary, i+1); //值還原 targetSummary.put("summaryMoney", ((BigDecimal)(targetSummary.get("summaryMoney"))).add(detailMoney)); tmpList.remove(currentDetail); //只取第一對合格資料,第一個元素代表詳細資料列表,第二個元素代表對應的摘要資料 if(resultList.size() == 2){ //從來源資料列表中去掉已經使用過的資料 detailList.removeAll((Collection<?>) resultList.get(0)); break; } } }else{ break; } } } public static LinkedList<Object> getResult(Map<String,List<Map<String,Object>>> sourceData){ List<Map<String,Object>> detailList = sourceData.get("detail"); List<Map<String,Object>> summaryList = sourceData.get("summary"); DetailValueComparator detailComparator = new DetailValueComparator(); SummaryValueComparator summaryComparator = new SummaryValueComparator(); Collections.sort(detailList,detailComparator); Collections.sort(summaryList,summaryComparator); int startIndex = 0; List<Map<String,Object>> remainSummaryList = new LinkedList<Map<String,Object>>(); LinkedList<Object> returnList = new LinkedList<Object>(); for(int i=0;i<summaryList.size();i++){ Map<String,Object> currentSummary = summaryList.get(i); LinkedList<Object> resultList = new LinkedList<Object>(); LinkedList<Map<String,Object>> tmpList = new LinkedList<Map<String,Object>>(); recursion(detailList, tmpList, resultList,currentSummary, startIndex); if(resultList.size() == 0){ remainSummaryList.add(currentSummary); } returnList.addAll(resultList); } Collections.sort(detailList,detailComparator); for(int i=0;i<remainSummaryList.size();i++){ //對最大的一筆交易進行拆分 int lastIndex = detailList.size()-1; Map<String,Object> lastDetail = detailList.get(lastIndex); Map<String,Object> targetSummary = remainSummaryList.get(i); LinkedList<Map<String,Object>> myTmpList = new LinkedList<Map<String,Object>>(); BigDecimal lastDetailMoney = (BigDecimal) lastDetail.get("detailMoney"); BigDecimal summaryMoney = (BigDecimal) targetSummary.get("summaryMoney"); BigDecimal sum = new BigDecimal(0); //待刪除列表 List<Map<String,Object>> listToRemove = new LinkedList<Map<String,Object>>(); for(int j=0;j<detailList.size();j++){ myTmpList.add(detailList.get(j)); Object t = detailList.get(j).get("detailMoney"); BigDecimal detailMoney = new BigDecimal(t.toString()); listToRemove.add(detailList.get(j)); sum = sum.add(detailMoney); if(!less(sum, summaryMoney)){ listToRemove.remove(detailList.get(j)); myTmpList.remove(detailList.get(j)); Map<String,Object> m = new HashMap<String,Object>(); //gap代表拼湊的金額 BigDecimal gap = summaryMoney.subtract(sum.subtract(detailMoney)); m.put("detailMoney", gap); m.put("ifBorrow", "yes"); //被拆交易的序號 m.put("borrowSerial", lastDetail.get("serialNo")); myTmpList.add(m); returnList.add(myTmpList); returnList.add(targetSummary); //更新被拆分交易的金額 lastDetail.put("detailMoney", lastDetailMoney.subtract(gap)); detailList.removeAll(listToRemove); if(equal(sum, summaryMoney)){ detailList.remove(lastDetail); } //重新排序,保證每次取到最大的交易明細進行拆分 Collections.sort(detailList, detailComparator); break; } } } return returnList; } public static boolean greater(BigDecimal d1,BigDecimal d2){ return d1.compareTo(d2)==1; } public static boolean equal(BigDecimal d1,BigDecimal d2){ return d1.compareTo(d2)==0; } public static boolean less(BigDecimal d1,BigDecimal d2){ return d1.compareTo(d2)==-1; } public static void main(String[] args) { Map<String,List<Map<String,Object>>> sourceData = new HashMap<String,List<Map<String,Object>>>(); List<Map<String,Object>> detailList = new LinkedList<Map<String,Object>>(); Map<String, Object> m1 = new HashMap<String, Object>(); m1.put("detailMoney", new BigDecimal(69)); m1.put("serialNo", 69); detailList.add(m1); m1 = new HashMap<String, Object>(); m1.put("detailMoney", new BigDecimal(35)); m1.put("serialNo", 35); detailList.add(m1); m1 = new HashMap<String, Object>(); m1.put("detailMoney", new BigDecimal(29)); m1.put("serialNo", 29); detailList.add(m1); m1 = new HashMap<String, Object>(); m1.put("detailMoney", new BigDecimal(26)); m1.put("serialNo", 26); detailList.add(m1); m1 = new HashMap<String, Object>(); m1.put("detailMoney", new BigDecimal(18)); m1.put("serialNo", 18); detailList.add(m1); m1 = new HashMap<String, Object>(); m1.put("detailMoney", new BigDecimal(12)); m1.put("serialNo", 12); detailList.add(m1); m1 = new HashMap<String, Object>(); m1.put("detailMoney", new BigDecimal(46)); m1.put("serialNo", 46); detailList.add(m1); m1 = new HashMap<String, Object>(); m1.put("detailMoney", new BigDecimal(92)); m1.put("serialNo", 92); detailList.add(m1); m1 = new HashMap<String, Object>(); m1.put("detailMoney", new BigDecimal(96)); m1.put("serialNo", 96); detailList.add(m1); m1 = new HashMap<String, Object>(); m1.put("detailMoney", new BigDecimal(75)); m1.put("serialNo", 75);