java編程算法經典案例


編程經典案例(持續更新中,敬請期待):

一、購物問題

  小明的女朋友最喜歡在網上買買買了,可是錢包里鈔票有限,不能想買啥就買啥。面對琳琅滿目的物品,她想買盡可能多的種類,每種只買一件,同時總價格還不能超過預算上限。於是她請小明寫程序幫她找出應該買哪些物品,並算出這些物品的總價格。

  輸入規范:
    每個輸入包含兩行。第一行是預算上限。第二行是用空格分隔的一組數字,代表每種物品的價格。所有數字都為正整數並且不會超過10000。

  輸出規范:
    對每個輸入,輸出應買物品的總價格。

  輸入示例1:
    100
    50 50
  輸出示例1:
    100

  輸入示例2:
    188
    50 42 9 15 105 63 14 30
  輸出示例2:
    160

代碼如下:

 
        
public class BuyTest {
    public static void main(String[] args) {
        //商品價格
        Integer[] ints = {50, 42, 9, 15, 105, 63, 14, 30};
        //預算上限
        Integer sum = 188;
        Integer num = calculate(ints, sum);
        System.out.println(num);
    }

    public static Integer calculate(Integer[] ints, Integer sum) {
        Integer count = 0;
        Integer value;
        sort(ints);
        for (Integer integer : ints) {
            value = count;
            count += integer;
            if (count > sum) {
                return value;
            }
        }
        return count;
    }

    public static void sort(Integer[] arr) {
        for (int i = 0; i < arr.length; i++) {
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[i] > arr[j]) {
                    int temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
        }
    }
}
 
        

 二、信息加密(數組偏移)問題

  李雷和韓梅梅坐前后排,上課想說話怕被老師發現,所以改為傳小紙條。為了不被老師發現他們紙條上說的是啥,他們約定了如下方法傳遞信息:
將26個英文字母(全為大寫),外加空格,一共27個字符分成3組,每組9個。也就是ABCDEFGHI是第一組,JKLMNOPQR是第二組,STUVWXYZ*是第三組(此處用*代表空格)。
然后根據傳遞紙條那天的日期,改變字母的位置。
先根據月份數m,以整個分組為單位進行循環左移,移動(m-1)次。
然后根據日期數d,對每個分組內的字符進行循環左移,移動(d-1)次。
以3月8日為例,首先移動分組,3月需要循環左移2次,變成:
STUVWXYZ*,ABCDEFGHI,JKLMNOPQR
然后每組內的字符,8日的話需要循環左移7次,最終的編碼為:
Z*STUVWXY,HIABCDEFG,QRJKLMNOP
對於要傳遞信息中的每個字符,用組號和組內序號兩個數字來表示。
如果在3月8日傳遞信息“HAPPY”,那么H位於第2組的第1個,A位於第2組第3個,P位於第3組第9個,Y位於第1組第9個,所以紙條上會寫成:
21 23 39 39 19
現在給定日期和需要傳遞的信息,請輸出應該寫在紙條上的編碼。

輸入規范:
  每個輸入包含兩行。第一行是用空格分隔的兩個數字,第一個數字是月份,第二個數字是日子。輸入保證是一個合法的日期。
  第二行為需要編碼的信息字符串,僅由A~Z和空格組成,長度不超過1024個字符。

輸出規范:
  對每個輸入,打印對應的編碼,數字之間用空格分隔,每個輸出占一行。

  輸入示例1:
  1 1
  HI
  輸出示例1:
  18 19

  輸入示例2:
  3 8
  HAPPY
  輸出示例2:
  21 23 39 39 19

  輸入示例3:
  2 14
  I LOVE YOU
  輸出示例3:
  35 25 18 12 29 31 25 23 12 28

代碼如下:

package com.tobiasy.toolkit.test;

public class MessageTest {
    public static void main(String[] args) {
        //月份數
        int month = 2;
        //日
        int day = 14;
        //所需要轉化的字符
        String text = "I LOVE YOU";
        start(month, day, text);
    }

    public static void start(int month, int day, String text) {
        char[] chars = text.toCharArray();
        for (char c : chars) {
            String value = getChar(month, day, c);
            System.out.print(value + ",");
        }
    }

    public static String getChar(int month, int day, char c) {
        month -= 1;
        day -= 1;
        char[][] chars = {
                {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'},
                {'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R'},
                {'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' '}};
        int monthFoward = month % chars.length;
        int dayFoward = day % chars[0].length;
        chars = sort(chars, monthFoward);
        for (int i = 0; i < chars.length; i++) {
            char[] arr = chars[i];
            sort(arr, dayFoward);
        }
        return getCharLocation(chars, c);
    }

    public static String getCharLocation(char[][] chars, char c) {
        String value = "";
        sys:
        for (int i = 0; i < chars.length; i++) {
            for (int j = 0; j < chars[i].length; j++) {
                char ch = chars[i][j];
                if (ch == c) {
                    value = ++i + "" + ++j;
                    break sys;
                }
            }
        }
        return value;
    }

    public static char[] sort(char[] chars, int dayFoward) {
        char[] arr = chars.clone();
        for (int i = 0; i < chars.length; i++) {
            int forward = i + dayFoward >= chars.length ? i + dayFoward - chars.length : i + dayFoward;
            chars[i] = arr[forward];
        }
        return chars;
    }

    public static char[][] sort(char[][] chars, int monthFoward) {
        char[][] arr = chars.clone();
        for (int i = 0; i < chars.length; i++) {
            int forward = i + monthFoward >= chars.length ? i + monthFoward - chars.length : i + monthFoward;
            chars[i] = arr[forward];
        }
        return chars;
    }
}

 三、老鼠走迷宮

  /**
     * 老鼠走迷宮
     * 說明:
     * 老鼠走迷宮是遞回求解的基本題型,我們在二維陣列中使用2表示迷宮牆壁,使用1表示老鼠行走的路徑,試以程
     * 式求出由入口至出口的路徑。
     *
     * 解法:
     * 老鼠的走法有上,下,左,右四個方向,在每前進一格之后就選一個方向前進,無法前進時退回選擇下一個可前
     * 進方向,如此在陣列中依序測試四個方向,直到走到出口為至,這是返回的基本題,請直接看程式應就可以理解 
     */
    static int[][] maze = {
        {2, 2, 2, 2, 2, 2, 2, 2},
        {2, 0, 0, 0, 0, 0, 0, 2},
        {2, 0, 2, 0, 2, 0, 0, 2},
        {2, 2, 0, 0, 0, 2, 0, 2},
        {2, 2, 0, 2, 0, 0, 0, 2},
        {2, 2, 0, 2, 2, 2, 2, 2},
        {2, 0, 0, 0, 0, 0, 0, 2},
        {2, 2, 2, 2, 2, 2, 2, 2}
    };

    static int startI = 1, startJ = 1;
    static int endI = 6, endJ = 6;
    static int success = 0;

    public static int walk() {
        int i, j;
        int length = maze[0].length;
        System.out.println("顯示迷宮:\n");
        for(i = 0; i < length; i++)
        {
            for(j = 0; j < length; j++)
            {
                if(maze[i][j] == 2) {
                    System.out.print("#");
                } else {
                    System.out.print(" ");
                }
            }
            System.out.println("\n");
        }

        if(visit(startI, startJ) == 0) {
            System.out.println("\n沒有找到出口!\n");
        } else {
            System.out.println("\n顯示路徑:\n");
            for(i = 0; i < length; i++)
            {
                for(j = 0; j < length; j++)
                {
                    if(maze[i][j] == 2) {
                        System.out.print("#");
                    } else if(maze[i][j] == 1) {
                        System.out.print("1");
                    } else {
                        System.out.print(" ");
                    }
                }
                System.out.println("\n");
            }
        }
        return 0;
    }
    private static int visit(int i, int j) {
        maze[i][j] = 1;
        if(i == endI && j == endJ) {
            success = 1;
        }
        if(success != 1 && maze[i][j+1] == 0) {
            visit(i, j+1);
        }
        if(success != 1 && maze[i+1][j] == 0) {
            visit(i+1, j);
        }
        if(success != 1 && maze[i][j-1] == 0) {
            visit(i, j-1);
        }
        if(success != 1 && maze[i-1][j] == 0) {
            visit(i-1, j);
        }
        if(success != 1) {
            maze[i][j] = 0;
        }
        return success;
    }

 

四、八皇后問題

說明:
西洋棋中的皇后可以直接前進,吃掉遇到的所有棋子,如果棋盤上有八個皇后,則這八個皇后如何相安無事的放置在棋盤上,
1970年與1971年,E.W.Dijkstra與N.Wirth曾經用這個問題來講解程式設計之技巧。

解法:
關於棋盤的問題,可以用遞回求解,然而如何減少遞回的次數?在八個皇后額問題中,不必要所有的個子都檢查過,例如若某列
檢查過,該列的其他格子就不用再檢查了,這個方法稱為分支修剪。

package com.tobiasy.toolkit.algorithm;

/**
 * @author tobiasy
 * @date 2018/10/29
 */
public class EightQueen {
    public static void main(String[] args) {
        queen();
    }
 
    static final Integer N = 8;
    /**
     * 同欄是否有皇后,1表示有
     */
    static int[] column = new int[N+1];
    /**
     * 右上至左下是否有皇后
     */
    static int[] rup = new int[2*N+1];
    /**
     *  左上至右下是否有皇后
     */
    static int[] lup = new int[2*N+1];
    static int[] queen = new int[N+1];
    /**
     * 解答編號
     */
    static int num;
 
 
    private static int queen() {
        int i;
        num = 0;
 
        for(i = 1; i <= N; i++)
        {
            column[i] = 1;
        }
 
        for(i = 1; i <= 2*N; i++)
        {
            rup[i] = lup[i] = 1;
        }
 
        backtrack(1);
 
        return 0;
    }
 
    private static void showAnswer() {
        int x, y;
        System.out.print("\n解答 "+ ++num+"\n");
        for(y = 1; y <= N; y++) {
            for(x = 1; x <= N; x++)
            {
                if(queen[y] == x)
                {
                    System.out.print("●");
                }
                else
                {
                    System.out.print("◎");
                }
            }
            System.out.print("\n");
        }
    }
    
    private static void backtrack(int i) {
        int j;
 
        if(i > N)
        {
            showAnswer();
        }
        else
        {
            for(j = 1; j <= N; j++)
            {
                if(column[j] == 1 && rup[i+j] == 1 && lup[i-j+N] == 1)
                {
                    queen[i] = j;
                    column[j] = rup[i+j] = lup[i-j+N] = 0;
                    backtrack(i+1);
                    column[j] = rup[i+j] = lup[i-j+N] = 1;
                }
            }
        }
    }
} 

 

五、字符串最長對稱子串

說明:
  輸入一段字符串,求其最長的對稱子串並輸出;例:
輸入:qabccbaff,輸出:abccba
出入:pop-upu, 輸出:pop和upu
import java.util.ArrayList;
import java.util.List;

/**
 * 找出最長對稱字符串
 *
 * @author tobiasy
 */
public class MaxSymmetric {
    public static void main(String[] args) {
        // TODO 輸出最長對稱字符串:goog
        String input1 = "google";
        // TODO 輸出最長對稱字符串:aba
        String input2 = "abada";
        // TODO 輸出2個最長對稱字符串:pop/upu
        String input3 = "pop-upu";

        start("sdghjdgzzgdah");
    }

    /**
     * 啟動方法
     * @param str
     */
    private static void start(String str) {
        List<String> list = maxSubSymmetric(str);
        if (list.isEmpty()) {
            System.err.println("沒有找到對稱字串!");
        }
        list.forEach(System.out::println);
    }

    /**
     *  獲取字符串中最長的對稱字串
     * @param str
     * @return
     */
    private static List<String> maxSubSymmetric(String str) {
        List<String> result = new ArrayList<>();
        List<String> list = allSubSymmetric(str);
        Integer length = 0;
        for (String s : list) {
            if (s.length() > length) {
                length = s.length();
            }
        }
        for (String s : list) {
            if (s.length() >= length) {
                result.add(s);
            }
        }
        return result;
    }

    /**
     * 獲取所有的對稱字串
     * @param str
     * @return
     */
    private static List<String> allSubSymmetric(String str) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i <= str.length(); i++) {
            for (int j = i; j <= str.length(); j++) {
                String sub = str.substring(i, j);
                if (check(sub)) {
                    list.add(sub);
                }
            }
        }
        return list;
    }

    /**
     * 判斷字符串是否對稱
     * @param str
     * @return
     */
    private static boolean check(String str) {
        if (str == null || str.length() <= 1) {
            return false;
        }
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) != str.charAt(str.length() - i - 1)) {
                return false;
            }
        }
        return true;
    }
}

 

 六、模擬手機號注冊

 
        
說明:
利用面向對象思路,設計和完成“手機號注冊校驗”業務邏輯。
你需要校驗多種情況的用戶輸入,如:
輸入:13812341234 提示注冊成功
輸入:1381234abcd 提示非法手機號碼
輸入:138 1234 1234 提示注冊成功
再次輸入:13812341234 提示該手機號已被注冊
-- 涉及到緩存請自行選擇

 

package com.tobiasy.toolkit.algorithm;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 用戶手機號注冊校驗
 *
 * @author tobiasy
 */
public class PhoneRegister {
    /**
     * 緩存地址
     */
    private static final String FILE_PATH = "E://test/data";

    public static void main(String[] args) {
        String phoneNum1 = "138 1234 1234";
        String phoneNum2 = "13812345abc";
        String phoneNum3 = "13812345678";
        String phoneNum4 = "1381234 5678";
        String phoneNum5 = "98765432101";

        start(phoneNum3);
    }

    /**
     * 啟動方法
     * @param phone
     */
    private static void start(String phone){
        if (check(phone)) {
            register(format(phone));
        } else {
            err("非法手機號碼!");
        }
        out(String.format("已注冊賬號:%s", getRegisterPhoneNums()));
    }

    private static void err(Object o) {
        System.err.println(o);
    }
    private static void out(Object o) {
        System.out.println(o);
    }

    /**
     * 創建文件
     * @return
     */
    private static boolean createFile() {
        File file = new File(FILE_PATH);
        if (!file.exists()) {
            try {
                File parentFile = file.getParentFile();
                if (!parentFile.exists()) {
                    parentFile.mkdirs();
                }
                file.createNewFile();
            } catch (IOException e) {
                return false;
            }
        }
        return true;
    }

    /**
     * 反序列化
     * @return
     */
    private static Object getRegisterPhoneNums(){
        return SerializableUtils.read(FILE_PATH);
    }

    /**
     * 格式化手機號碼
     * @param phoneNum
     * @return
     */
    private static String format(String phoneNum){
        return phoneNum.replaceAll("( )\\1*", "");
    }

    /**
     * 注冊
     * @param phoneNum
     */
    public static void register(String phoneNum) {
        try {
            if (!createFile()) {
                err("緩存文件地址錯誤!");
            } else {
                List<String> data;
                Object object = SerializableUtils.read(FILE_PATH);
                if (object != null) {
                    data = (List<String>) object;
                    boolean contains = data.contains(phoneNum);
                    if (contains) {
                        err("該手機號已被注冊!");
                    } else {
                        data.add(phoneNum);
                        out("注冊成功!");
                    }
                } else {
                    data = new ArrayList<>();
                    data.add(phoneNum);
                    out("注冊成功!");
                }
                SerializableUtils.write(data, FILE_PATH);
            }
        } catch (Exception e) {
            err("序列化異常!");
        }
    }

    /**
     * 校驗手機號碼是否正確
     * @param phoneNum
     * @return
     */
    private static boolean check(String phoneNum) {
        return phoneNum.matches("1(3[0-9]|5[189]|8[6789])( )?[0-9]{4}( )?[0-9]{4}");
    }
}

 工具類

package com.tobiasy.toolkit.algorithm;
import java.io.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * JDK自帶序列化操作 * * @author tobiasy */ public class SerializableUtils { /** * 序列化 將對象存儲到文件中 * * @param obj 序列化對象,必須實現可序列化接口 * @param path 序列化路徑 * @return */ public static boolean write(Object obj, String path) { boolean f; File file = getFile(path); OutputStream out = null; ObjectOutputStream objout = null; try { out = new FileOutputStream(file); objout = new ObjectOutputStream(out); objout.writeObject(obj); f = true; } catch (IOException e) { f = false; e.printStackTrace(); } finally { close(objout); close(out); } return f; } /** * 反序列化 讀取存入文件中的對象 * * @param pathname 反序列化路徑 * @return */ public static Object read(String pathname) { Object obj = null; File file = new File(pathname); InputStream in = null; ObjectInputStream objin = null; try { in = new FileInputStream(file); objin = new ObjectInputStream(in); obj = objin.readObject(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (EOFException e) { } catch (IOException e) { e.printStackTrace(); } finally { close(objin); close(in); } return obj; } public static File getFile(String filePath) { File file = new File(filePath); if (!file.exists()) { try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } return file; } /** * 流的關閉操作 * * @param obj 流對象 */ public static void close(Object obj) { if (obj != null) { try { invoke(obj, "close"); } catch (RuntimeException e) { e.printStackTrace(); } } } /** * 執行一個無參方法 * * @param obj 操作對象 * @param methodName 屬性名 * @return Object * @throws RuntimeException */ public static Object invoke(Object obj, String methodName) throws RuntimeException { if (obj == null || methodName == null) { return null; } Object value = null; try { Method getMethod = obj.getClass().getMethod(methodName); if (getMethod == null) { return null; } getMethod.setAccessible(true); value = getMethod.invoke(obj); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } return value; } }

 

 Java自學教程推薦

1、Java自學教程(java,python,大數據,前端,計算機書籍)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM