1. 程式人生 > 其它 >6.25_開啟轉盤鎖_heapq(python)_HashMap(java)_char**(c的賦值)

6.25_開啟轉盤鎖_heapq(python)_HashMap(java)_char**(c的賦值)

6.25_開啟轉盤鎖:

你有一個帶有四個圓形撥輪的轉盤鎖。每個撥輪都有10個數字: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 。每個撥輪可以自由旋轉:例如把 '9' 變為'0','0' 變為 '9' 。每次旋轉都只能旋轉一個撥輪的一位數字。

鎖的初始數字為 '0000' ,一個代表四個撥輪的數字的字串。

列表 deadends 包含了一組死亡數字,一旦撥輪的數字和列表裡的任何一個元素相同,這個鎖將會被永久鎖定,無法再被旋轉。

字串 target 代表可以解鎖的數字,你需要給出解鎖需要的最小旋轉次數,如果無論如何不能解鎖,返回 -1 。

示例 1:

輸入:deadends = ["0201","0101","0102","1212","2002"], target = "0202"
輸出:6
解釋:
可能的移動序列為 "0000" -> "1000" -> "1100" -> "1200" -> "1201" -> "1202" -> "0202"。
注意 "0000" -> "0001" -> "0002" -> "0102" -> "0202" 這樣的序列是不能解鎖的,
因為當撥動到 "0102" 時這個鎖就會被鎖定。


示例 2:

輸入: deadends = ["8888"], target = "0009"
輸出:1
解釋:
把最後一位反向旋轉一次即可 "0000" -> "0009"。


示例 3:

輸入: deadends = ["8887","8889","8878","8898","8788","8988","7888","9888"], target = "8888"
輸出:-1
解釋:
無法旋轉到目標數字且不被鎖定。


示例 4:

輸入: deadends = ["0000"], target = "8888"
輸出:-1

提示:

1 <=deadends.length <= 500
deadends[i].length == 4
target.length == 4
target 不在 deadends 之中
target 和 deadends[i] 僅由若干位數字組成

連結:https://leetcode-cn.com/problems/open-the-lock

1、java

import java.util.*;

class Solution {
    public static int openLock(String[] deadends, String target) {
        if ("0000".equals(target)) {
            return 0;
        }

        Set<String> dead = new HashSet<>();
        for (String deadend : deadends) {
            dead.add(deadend);
        }
        
if (dead.contains("0000")) { return -1; } int step = 0; Queue<String> queue = new LinkedList<String>(); queue.offer("0000"); Set<String> seen = new HashSet<String>(); seen.add("0000"); while (!queue.isEmpty()) { ++step; int size = queue.size(); for (int i = 0; i < size; ++i) { String status = queue.poll(); for (String nextStatus : get(status)) { if (!seen.contains(nextStatus) && !dead.contains(nextStatus)) { if (nextStatus.equals(target)) { return step; } queue.offer(nextStatus); seen.add(nextStatus); } } } } return -1; } public static char numPrev(char x) { return x == '0' ? '9' : (char) (x - 1); } public static char numSucc(char x) { return x == '9' ? '0' : (char) (x + 1); } // 列舉 status 通過一次旋轉得到的數字 public static List<String> get(String status) { List<String> ret = new ArrayList<String>(); char[] array = status.toCharArray(); for (int i = 0; i < 4; ++i) { char num = array[i]; array[i] = numPrev(num); ret.add(new String(array)); array[i] = numSucc(num); ret.add(new String(array)); array[i] = num; } return ret; } public static void main(String[] args) { String[] deadends = {"0201","0101","0102","1212","2002"}; String target = "0202"; System.out.println(openLock(deadends, target)); } }
View Code
// HashSet集合,contains
if (dead.contains("0000")) {
            return -1;
        }
Queue<String> queue = new LinkedList<String>();
// 新增元素
queue.offer("a");
// 遍歷元素
for(String q : queue){
            System.out.println(q);
        }
// 返回第一個元素,並在佇列中刪除
queue.poll();
queue.element(); //返回第一個元素
queue.peek(); //返回第一個元素 


LinkedList<String> sites = new LinkedList<String>();
sites.add("Taobao");
// 使用 addFirst() 在頭部新增元素
sites.addFirst("Wiki");
// 使用 addLast() 在尾部新增元素
sites.addLast("Wiki");
// 使用 removeFirst() 移除頭部元素
sites.removeFirst();
// 使用 removeLast() 移除尾部元素
sites.removeLast();
// 使用 getFirst() 獲取頭部元素
System.out.println(sites.getFirst());
// 使用 getLast() 獲取尾部元素
System.out.println(sites.getLast());
// 迭代元素
for (int size = sites.size(), i = 0; i < size; i++) {
            System.out.println(sites.get(i));
        }
// 建立 HashMap 物件 Sites
HashMap<Integer, String> Sites = new HashMap<Integer, String>();
// 新增鍵值對
Sites.put(1, "Google");

// 使用 get(key) 方法來獲取 key 對應的 value:
Sites.get(3)
// remove(key) 方法來刪除 key 對應的鍵值對(key-value):
Sites.remove(4);
// 刪除所有鍵值對(key-value)可以使用 clear 方法:
Sites.clear();
Sites.size();
// 輸出 key 和 value
for (Integer i : Sites.keySet()) {
            System.out.println("key: " + i + " value: " + Sites.get(i));
        }
        // 返回所有 value 值
for(String value: Sites.values()) {
          // 輸出每一個value
          System.out.print(value + ", ");
        }

2、c++

//#include "iostream"
//#include "vector"
//#include "unordered_set"
//#include "queue"
//using namespace std;
//
//class Solution {
//public:
//    int openLock(vector<string>& deadends, const string& target) {
//        if (target == "0000") {
//            return 0;
//        }
//
//        unordered_set<string> dead(deadends.begin(), deadends.end());
//        if (dead.count("0000")) {
//            return -1;
//        }
//
//        auto num_prev = [](char x) -> char {
//            return (x == '0' ? '9' : x - 1);
//        };
//        auto num_succ = [](char x) -> char {
//            return (x == '9' ? '0' : x + 1);
//        };
//
//        // 列舉 status 通過一次旋轉得到的數字
//        auto get = [&](string& status) -> vector<string> {
//            vector<string> ret;
//            for (int i = 0; i < 4; ++i) {
//                char num = status[i];
//                status[i] = num_prev(num);
//                ret.push_back(status);
//                status[i] = num_succ(num);
//                ret.push_back(status);
//                status[i] = num;
//            }
//            return ret;
//        };
//
//        queue<pair<string, int>> q;
//        q.emplace("0000", 0);
//        unordered_set<string> seen = {"0000"};
//
//        while (!q.empty()) {
//            auto [status, step] = q.front();
//            q.pop();
//            for (auto&& next_status: get(status)) {
//                if (!seen.count(next_status) && !dead.count(next_status)) {
//                    if (next_status == target) {
//                        return step + 1;
//                    }
//                    q.emplace(next_status, step + 1);
//                    seen.insert(move(next_status));
//                }
//            }
//        }
//
//        return -1;
//    }
//};
//
//// 報錯的,為啥??
//int main() {
//    vector<string> deadends = {"0201","0101","0102","1212","2002"};
//    string target = "0202";
//    cout << Solution().openLock(deadends, target) << endl;
//}

#include "iostream"
#include "vector"
#include "unordered_set"
#include "queue"
using namespace std;

struct AStar {
    // 計算啟發函式
    static int getH(const string& status, const string& target) {
        int ret = 0;
        for (int i = 0; i < 4; ++i) {
            int dist = abs(int(status[i]) - int(target[i]));
            ret += min(dist, 10 - dist);
        }
        return ret;
    };

    AStar(const string& status, const string& target, int g): status_{status}, g_{g}, h_{getH(status, target)} {
        f_ = g_ + h_;
    }

    bool operator< (const AStar& that) const {
        return f_ > that.f_;
    }

    string status_;
    int f_, g_, h_;
};

class Solution {
public:
    int openLock(vector<string>& deadends, string target) {
        if (target == "0000") {
            return 0;
        }

        unordered_set<string> dead(deadends.begin(), deadends.end());
        if (dead.count("0000")) {
            return -1;
        }

        auto num_prev = [](char x) -> char {
            return (x == '0' ? '9' : x - 1);
        };
        auto num_succ = [](char x) -> char {
            return (x == '9' ? '0' : x + 1);
        };

        auto get = [&](string& status) -> vector<string> {
            vector<string> ret;
            for (int i = 0; i < 4; ++i) {
                char num = status[i];
                status[i] = num_prev(num);
                ret.push_back(status);
                status[i] = num_succ(num);
                ret.push_back(status);
                status[i] = num;
            }
            return ret;
        };

        priority_queue<AStar> q;
        q.emplace("0000", target, 0);
        unordered_set<string> seen = {"0000"};

        while (!q.empty()) {
            AStar node = q.top();
            q.pop();
            for (auto&& next_status: get(node.status_)) {
                if (!seen.count(next_status) && !dead.count(next_status)) {
                    if (next_status == target) {
                        return node.g_ + 1;
                    }
                    q.emplace(next_status, target, node.g_ + 1);
                    seen.insert(move(next_status));
                }
            }
        }

        return -1;
    }
};

// 這個就可以執行!!
int main() {
    vector<string> deadends = {"0201","0101","0102","1212","2002"};
    string target = "0202";
    cout << Solution().openLock(deadends, target) << endl;
}
View Code

3、c

#include "stdio.h"
#include ".\lib\uthash-master\src\uthash.h" /* UT_hash_handle */

struct HashTable {
    char str[5];
    UT_hash_handle hh;
};

struct Node {
    char str[5];
    int val;
};

char num_prev(char x) {
    return (x == '0' ? '9' : x - 1);
}

char num_succ(char x) {
    return (x == '9' ? '0' : x + 1);
}

// 列舉 status 通過一次旋轉得到的數字
char** getNextStatus(char* status, int* retSize) {
    char** ret = malloc(sizeof(char*) * 8);
    *retSize = 0;
    for (int i = 0; i < 4; ++i) {
        char num = status[i];
        status[i] = num_prev(num);
        ret[(*retSize)] = malloc(sizeof(char) * 5);
        strcpy(ret[(*retSize)++], status);
        status[i] = num_succ(num);
        ret[(*retSize)] = malloc(sizeof(char) * 5);
        strcpy(ret[(*retSize)++], status);
        status[i] = num;
    }
    return ret;
}

int openLock(char** deadends, int deadendsSize, char* target) {
    char str_0[5] = "0000";
    if (strcmp(target, str_0) == 0) {
        return 0;
    }
    struct HashTable* dead = NULL;
    struct HashTable* tmp;
    for (int i = 0; i < deadendsSize; i++) {
        HASH_FIND(hh, dead, deadends[i], sizeof(char) * 5, tmp);
        if (tmp == NULL) {
            tmp = malloc(sizeof(struct HashTable));
            strcpy(tmp->str, deadends[i]);
            HASH_ADD(hh, dead, str, sizeof(char) * 5, tmp);
        }
    }
    HASH_FIND(hh, dead, str_0, sizeof(char) * 5, tmp);

    if (tmp != NULL) {
        return -1;
    }

    struct Node q[10001];
    int left = 0, right = 0;
    strcpy(q[right].str, str_0);
    q[right++].val = 0;

    struct HashTable* seen = NULL;
    tmp = malloc(sizeof(struct HashTable));
    strcpy(tmp->str, str_0);
    HASH_ADD(hh, seen, str, sizeof(char) * 5, tmp);

    while (left < right) {
        char* status = q[left].str;
        int step = q[left++].val;
        int nextStatusSize;
        char** nextStatus = getNextStatus(status, &nextStatusSize);
        for (int i = 0; i < nextStatusSize; i++) {
            struct HashTable *tmp1, *tmp2;
            HASH_FIND(hh, dead, nextStatus[i], sizeof(char) * 5, tmp1);
            HASH_FIND(hh, seen, nextStatus[i], sizeof(char) * 5, tmp2);
            if (tmp1 == NULL && tmp2 == NULL) {
                if (strcmp(nextStatus[i], target) == 0) {
                    return step + 1;
                }
                strcpy(q[right].str, nextStatus[i]);
                q[right++].val = step + 1;
                tmp = malloc(sizeof(struct HashTable));
                strcpy(tmp->str, nextStatus[i]);
                HASH_ADD(hh, seen, str, sizeof(char) * 5, tmp);
            }
        }
    }

    return -1;
}

int main() {
    char* deadends[] = {"0201", "0101", "0102", "1212", "2002"};
    int deadendsSize = sizeof(deadends) / sizeof(deadends[0]);
    char* target = "0202";
    printf("%d ", openLock(deadends, deadendsSize, target));
}
View Code

4、python

import heapq #
from typing import Generator, List


class AStar:
    # 計算啟發函式
    @staticmethod
    def getH(status: str, target: str) -> int:
        ret = 0
        for i in range(4):
            dist = abs(int(status[i]) - int(target[i]))
            ret += min(dist, 10 - dist)
        return ret

    def __init__(self, status: str, target: str, g: str) -> None:
        self.status = status
        self.g = g
        self.h = AStar.getH(status, target)
        self.f = self.g + self.h

    def __lt__(self, other: "AStar") -> bool:
        return self.f < other.f

class Solution:
    def openLock(self, deadends: List[str], target: str) -> int:
        if target == "0000":
            return 0

        dead = set(deadends)
        if "0000" in dead:
            return -1

        def num_prev(x: str) -> str:
            return "9" if x == "0" else str(int(x) - 1)

        def num_succ(x: str) -> str:
            return "0" if x == "9" else str(int(x) + 1)

        def get(status: str) -> Generator[str, None, None]:
            s = list(status)
            for i in range(4):
                num = s[i]
                s[i] = num_prev(num)
                yield "".join(s)
                s[i] = num_succ(num)
                yield "".join(s)
                s[i] = num

        q = [AStar("0000", target, 0)]
        seen = {"0000"}
        while q:
            node = heapq.heappop(q)
            for next_status in get(node.status):
                if next_status not in seen and next_status not in dead:
                    if next_status == target:
                        return node.g + 1
                    heapq.heappush(q, AStar(next_status, target, node.g + 1))
                    seen.add(next_status)

        return -1


if __name__ == "__main__":
    # openLock(self, deadends: List[str], target: str)
    deadends = ["0201", "0101", "0102", "1212", "2002"]
    target = "0202"
    print(Solution().openLock(deadends, target))
View Code

Python的富比較方法包括__lt__、__gt__分別表示:小於、大於,對應的操作運算子為:“<”、“>”。

當一個定義另一個未定義時,未定義的操作執行時會呼叫已經定義的方法求反。這個與__eq__和__ne__的關係還是有較大的不同。

heapq堆的常用方法:

import heapq

hList = []
# heapq.heappush(heap, item), heap為定義堆,item增加的元素
heapq.heappush(hList, 2)
print(hList)
# heapq.heapify(list), 將列表轉換為堆
exampleList = [1,2,3,5,1,5,8,9,6]
print(exampleList)
heapq.heapify(exampleList) # 跟列表區別???
print(exampleList, type(exampleList))
# heapq.heappop(heap),刪除並返回最小值,
# 因為堆的特徵是heap[0]永遠是最小的元素,所以一般都是刪除第一個元素。
print(heapq.heappop(exampleList))
print("heappop: ", exampleList)
# heapq.heapreplace(heap.item), 刪除並返回最小元素值,新增新的元素值
print(heapq.heapreplace(exampleList, 99))
print("heapreplace: ", exampleList)
# heapq.heappushpop(list,item)
# 判斷新增元素值與堆的第一個元素值對比;如果大,則刪除並返回第一個元素,然後新增新元素值item.
# 如果小,則返回item.  原堆不變。
print(heapq.heappushpop(exampleList,6))
print("heappushpop:", exampleList)
# heapq.merge(…),將多個堆合併
h = [1000]
heapq.merge(h,exampleList) # 不改變原來的列表
print("merge: ", h)
print("merge: ", exampleList)
for i in heapq.merge(h,exampleList):
    print(i,end=" ")
# heapq.nlargest(n,heap), 查詢堆中的最大n個元素
print(heapq.nlargest(3,exampleList))

# heapq.nsmallest(n,heap),查詢堆中的最小n個元素
print(heapq.nsmallest(3,exampleList))

# 使用heapq編寫優先順序佇列
class PriorityQueue:
    def __init__(self):
        self.__queue = []
        self.__index = 0

    def push(self, item, priority):
        heapq.heappush(self.__queue, (-priority, self.__index, item))
        # 第一個引數:新增進的目標序列
        # 第二個引數:將一個元組作為整體新增進序列,目的是為了方便比較
        # 在priority相等的情況下,比較_index
        # priority為負數使得新增時按照優先順序從大到小排序,因為堆排序的序列的第一個元素永遠是最小的
        self.__index += 1

    def pop(self):
        # 返回按照-priority 和 _index 排序後的第一個元素(是一個元組)的最後一個元素(item)
        return heapq.heappop(self.__queue)[-1]



q = PriorityQueue()
q.push("bar", 2)
q.push("foo", 1)
q.push("gork", 3)
q.push("new", 1)
print(q.pop())
print(q.pop())
print(q.pop())
print(q.pop())

"""
gork  # 優先順序最高
bar   # 優先順序第二
foo   # 優先順序與new相同,比較index,因為先加入,index比new小,所以排在前面
new
"""

# 回頭用到再仔細研究佇列