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

6.25_打开转盘锁_heapq(python)_HashMap(java)_char**(c的赋值)
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

6.25_打开转盘锁_heapq(python)_HashMap(java)_char**(c的赋值)

 

 

// HashSet集合,contains
if (dead.contains("0000")) {
            return -1;
        }

6.25_打开转盘锁_heapq(python)_HashMap(java)_char**(c的赋值)

 

 

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));
        }

6.25_打开转盘锁_heapq(python)_HashMap(java)_char**(c的赋值)

 

 

// 创建 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++

6.25_打开转盘锁_heapq(python)_HashMap(java)_char**(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

6.25_打开转盘锁_heapq(python)_HashMap(java)_char**(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

6.25_打开转盘锁_heapq(python)_HashMap(java)_char**(c的赋值)

 

 4、python

6.25_打开转盘锁_heapq(python)_HashMap(java)_char**(c的赋值)
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

6.25_打开转盘锁_heapq(python)_HashMap(java)_char**(c的赋值)

 

 Python的富比较方法包括__lt__、__gt__分别表示:小于、大于,对应的操作运算符为:“<”、“>”。

当一个定义另一个未定义时,未定义的操作执行时会调用已经定义的方法求反。这个与__eq__和__ne__的关系还是有较大的不同。

6.25_打开转盘锁_heapq(python)_HashMap(java)_char**(c的赋值)

 

 6.25_打开转盘锁_heapq(python)_HashMap(java)_char**(c的赋值)

 

 6.25_打开转盘锁_heapq(python)_HashMap(java)_char**(c的赋值)

 

 

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
"""

# 回头用到再仔细研究队列

6.25_打开转盘锁_heapq(python)_HashMap(java)_char**(c的赋值)

 

上一篇:PHP依赖注入容器【pimple】


下一篇:LeetCode 786. 第 K 个最小的素数分数