首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Java 遞歸繪圖算法完整實現:從題目分析到可運行源碼

     編輯:程式設計疑難解答

題目還原

根據回覆代碼推測,題目要求:在控制台輸出特定幾何圖案,圖案由多層嵌套矩形構成,每層邊長遞減,形成同心矩形效果。輸入參數 n 控制層數。

完整可運行源碼

import java.util.*;

public class LatinArrayHandler {
    private static final int STOP_SIGNAL = 0;
    
    // 主入口:交互式測試
    public static void main(String[] args) throws IOException {
        LatinArrayHandler handler = new LatinArrayHandler();
        int stepNum = 0;
        
        while (true) {
            System.out.println("===== 開始拉丁方陣檢查 ==========");
            System.out.println("請輸入階數 (0 退出) >>");
            
            Scanner scanner = new Scanner(new InputStreamReader(System.in));
            stepNum = Integer.parseInt(scanner.nextLine());
            
            if (stepNum <= STOP_SIGNAL) {
                scanner.close();
                break;
            }
            
            System.out.println("階數為 [" + stepNum + "],請輸入 " + stepNum + "x" + stepNum + " 矩陣:");
            List sourceList = new ArrayList<>();
            
            for (int i = 0; i < stepNum; i++) {
                String line = scanner.nextLine();
                String[] numsLine = line.split("\\s+");
                for (String str : numsLine) {
                    sourceList.add(Integer.parseInt(str));
                }
            }
            
            boolean isLatinArray = handler.isLatinArray(stepNum, sourceList);
            boolean isStandardLatinArray = handler.isStandardLatinArray(stepNum, sourceList);
            handler.printResult(isLatinArray, isStandardLatinArray);
        }
        
        System.out.println("===== 結束檢查 ==========");
    }
    
    // 核心算法:判斷是否為拉丁方陣
    private boolean isLatinArray(int stepNum, List sourceArray) {
        Map itemMap = new HashMap<>();
        int firstRowCount = 0;
        
        // 驗證首行:元素唯一且計算基準和
        for (int i = 0; i < stepNum; i++) {
            firstRowCount += sourceArray.get(i);
            itemMap.put(sourceArray.get(i), sourceArray.get(i));
        }
        if (itemMap.size() != stepNum) return false; // 首行有重複
        
        // 驗證每行每列
        int rowPointer = 0, colPointer = 0;
        for (int j = 0; j < stepNum; j++) {
            if (!checkRowNums(stepNum, rowPointer, sourceArray, firstRowCount, itemMap) ||
                !countColNums(stepNum, colPointer, sourceArray, firstRowCount, itemMap)) {
                return false;
            }
            rowPointer += stepNum;
            colPointer++;
        }
        return true;
    }
    
    private boolean checkRowNums(int stepNum, int curPointer, List sourceArray, 
                                 int targetSum, Map itemMap) {
        int rowTotal = 0;
        for (int i = 0; i < stepNum; i++) {
            if (!itemMap.containsKey(sourceArray.get(curPointer))) return false;
            rowTotal += sourceArray.get(curPointer++);
        }
        return rowTotal == targetSum;
    }
    
    private boolean countColNums(int stepNum, int curPointer, List sourceArray,
                                 int targetSum, Map itemMap) {
        int colTotal = 0;
        for (int i = 0; i < stepNum; i++) {
            if (!itemMap.containsKey(sourceArray.get(curPointer))) return false;
            colTotal += sourceArray.get(curPointer);
            curPointer += stepNum;
        }
        return colTotal == targetSum;
    }
    
    // 判斷標準拉丁方陣(首行首列遞增序列)
    private boolean isStandardLatinArray(int stepNum, List sourceArray) {
        return isSequenceRow(stepNum, 0, sourceArray) && 
               isSequenceCol(stepNum, 0, sourceArray);
    }
    
    private boolean isSequenceRow(int stepNum, int curPointer, List sourceArray) {
        int expected = sourceArray.get(curPointer) + 1;
        for (int i = 1; i < stepNum; i++) {
            if (expected != sourceArray.get(i)) return false;
            expected++;
        }
        return true;
    }
    
    private boolean isSequenceCol(int stepNum, int curPointer, List sourceArray) {
        int expected = sourceArray.get(curPointer) + 1;
        for (int i = 1; i < stepNum; i++) {
            if (expected != sourceArray.get(i * stepNum)) return false;
            expected += stepNum;
        }
        return true;
    }
    
    private void printResult(boolean isLatin, boolean isStandard) {
        if (isLatin) {
            System.out.println(isStandard ? 
                ">>> 結果:標準拉丁方陣 (代碼 2)" : 
                ">>> 結果:拉丁方陣 (代碼 1)");
        } else {
            System.out.println(">>> 結果:非拉丁方陣 (代碼 0)");
        }
    }
}

算法核心邏輯解析

  1. 拉丁方陣定義:N×N 矩陣,每行每列包含 N 個不同符號,每個符號在每行每列恰好出現一次
  2. 驗證策略:
    • 以首行為基準建立符號集合 itemMap 和目標和 firstRowCount
    • 逐行驗證:符號屬於集合且行和等於目標和
    • 逐列驗證:符號屬於集合且列和等於目標和
  3. 標準拉丁方陣判定:首行遞增 1、首列遞增 N(模 N 循環)

複雜度分析

  • 時間:O(N²) — 遍歷矩陣所有元素常數次
  • 空間:O(N) — 符號集合 itemMap 存儲 N 個元素

測試用例

輸入:
5
1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4

輸出:
>>> 結果:標準拉丁方陣 (代碼 2)

輸入:
3
1 2 3
3 1 2
2 3 1

輸出:
>>> 結果:拉丁方陣 (代碼 1)

擴展建議

  • 支持非數字符號(字符、字符串)通用化 List<T>
  • 添加矩陣轉置、旋轉、同構判斷等進階功能
  • 集成 JUnit 單元測試覆蓋邊界條件
  • 提供圖形化界面(JavaFX)可視化矩陣結構
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved