[算法]能否成环

能否成环

题目地址

题目描述

Description

Given an array of strings A[ ], determine if the strings can be chained together to form a circle. A string X can be chained together with another string Y if the last character of X is same as first character of Y. If every string of the array can be chained, it will form a circle. For example, for the array arr[] = {“for”, “geek”, “rig”, “kaf”} the answer will be Yes as the given strings can be chained as “for”, “rig”, “geek” and “kaf”.

Input

The first line of input contains an integer T denoting the number of test cases. Then T test cases follow.

The first line of each test case contains a positive integer N, denoting the size of the array.

The second line of each test case contains a N space seprated strings, denoting the elements of the array A[ ].

1 <= T

0 < N

0 < A[i]

Output

If chain can be formed, then print 1, else print 0.

Sample Input 1

2
3
abc bcd cdf
4
ab bc cd da

Sample Output 1

0
1

题目解析

任意选择一个字符串数组中的元素,并按照首尾字母是否相同将元素首尾相连,如果可以刚刚好形成一个环则返回1,否则返回0

测试用例

Input: arr[] = {"geek", "king"}
Output: Yes, the given strings can be chained.
Note that the last character of first string is same
as first character of second string and vice versa is
also true.

Input: arr[] = {"for", "geek", "rig", "kaf"}
Output: Yes, the given strings can be chained.
The strings can be chained as "for", "rig", "geek" 
and "kaf"

Input: arr[] = {"aab", "bac", "aaa", "cda"}
Output: Yes, the given strings can be chained.
The strings can be chained as "aaa", "aab", "bac" 
and "cda"

Input: arr[] = {"aaa", "bbb", "baa", "aab"};
Output: Yes, the given strings can be chained.
The strings can be chained as "aaa", "aab", "bbb" 
and "baa"

Input: arr[] = {"aaa"};
Output: Yes

Input: arr[] = {"aaa", "bbb"};
Output: No

Input  : arr[] = ["abc", "efg", "cde", "ghi", "ija"]
Output : Yes
These strings can be reordered as, “abc”, “cde”, “efg”,
“ghi”, “ija”

Input : arr[] = [“ijk”, “kji”, “abc”, “cba”]  
Output : No

注意:

  1. 有单独一个字符串成环的情况
  2. 也有局部成环的情况
  3. 多个环连接在一起的情况

对于以上几点注意分别有几种常见的错误思路

错误思路:

  1. 统计首尾字符数量

    对首尾字符的数量进行分别统计,若每个字符的开头数量等于结尾数量则认为满足条件,对于可以单独成环的如"a",“b”,单独做判断

    错误原因,无法判别出局部成环的情况,如[“ijk”, “kji”, “abc”, “cba”]

    错误代码
    from collections import defaultdict
    if __name__ == '__main__':
     for _ in range(int(input())):
            _ = int(input())
            arr = input().strip().split(" ")
            dict1 = defaultdict(lambda: [0, 0])  # 默认值设为0
            key_set = set()  # 创建一个set,收集单独成环的字符
            for x in arr:  # 统计每个字符的开头结尾的数量
                if x[0] == x[-1]:
                    key_set.add(x[0])
                else:
                    dict1[x[0]][0] += 1
                    dict1[x[-1]][-1] += 1
            if len(dict1) == 0 and len(key_set) == 1:  # 若只有一个重复的  a
                print(1)
            else:
                if key_set.issubset(dict1.keys()):  # 若单独成环的字符全都出现过
                    for k, v in dict1.items():
                        if v[0] != v[1]:
                            print(0)
                            break
                    else:
                        print(1)
                else:
                    print(0)
    
    
  2. 用两个list遍历

    list1储存输入数组,list2储存结果,每次从list1中取出一个元素放入list2中,并继续在list1中寻找符合开头字母等于上一个放进去的元素结尾字母的元素,直到列表为空或者无法选择为止.但这种方法也有问题,具体问题如下

    如:l = [“axb”, “bxc”, “cxd”, “dxa”, “dxe”, “exd”] 和l =[“axb”, “bxc”, “cxd”, “dxe”, “dxa”, “exd”]

    同样的字符序列,如果采用这种方法会得到不同的结果

    错误代码

    注意:这里代码虽然错误,但依然可以AC,因为用例是不全面的.使用两个list的时,重点在 target_char = res_l[-1][-1]这行,一定要写到for循环里面则正好符合了用例输出,否则不对
    这种思路一定是有问题的,只是可以AC

    if __name__ == '__main__':
     for _ in range(int(input())):
         _ = int(input())
         l = input().strip().split(" ")
         # l = ["axb", "bxc", "cxd", "dxa", "dxe", "exd"]
         res_l = l[0:1]
         l = l[1:]
         flag = True
         while len(l) > 0 and flag:
             flag = False
             for x in l:
                 target_char = res_l[-1][-1]  # 每次寻找最后一个字符串的最后一个字符
                 if x[0] == target_char:
                     res_l.append(x)
                     l.remove(x)
                     flag = True
         if flag and res_l[0][0] == res_l[-1][-1]:  # 如果数组的第一个字符等于最后一个字符,就成环了,否则就是链
             print(1)
         else:
             print(0)
    
    

思路解析

在这里插入图片描述

  1. 这道题的正确方法是使用图的结构

    如果存在欧拉回路,则可以形成链,否则不能。

    注意,有向图只有在每个顶点的入度和出度相同时才具有欧拉回路,并且所有非零度顶点都形成一个强连通分量。

    下面是算法的详细步骤。

    1)创建顶点数等于字母表大小的有向图g。我们在下面的程序中创建了一个有26个顶点的图。

    2)对给定字符串数组中的每个字符串执行以下操作。

    ……a)在给定图形的第一个字符到最后一个字符之间添加一条边。

    3)如果创建的图具有欧拉回路,则返回true,否则返回false。

这里什么欧拉回路我也没看懂

代码实现

Java
import java.util.*;

class Main {
    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        int t = s.nextInt();
        s.nextLine();
        while (t-- > 0) {
            int n = Integer.parseInt(s.nextLine());
            String[] str = s.nextLine().trim().split(" ");
            Graph g = new Graph(26);
            for (int i = 0; i < str.length; i++) {
                char start = str[i].charAt(0);
                char end = str[i].charAt(str[i].length() - 1);
                g.addEdge(start - 'a', end - 'a');
            }
            boolean res = g.isEulerian();
            if (res) {
                System.out.println(1);
            } else {
                System.out.println(0);
            }
        }
    }
}

class Graph {
    ArrayList<ArrayList<Integer>> list = new ArrayList<>();
    int[] count = new int[26];
    int V;

    Graph(int v) {
        this.V = v;
        for (int i = 0; i < v; i++) {
            list.add(new ArrayList<Integer>());
        }
    }

    public void addEdge(int i, int j) {
        ArrayList<Integer> temp = list.get(i);
        temp.add(j);
        list.add(temp);
        count[j]++;
    }

    public boolean isEulerian() {
        if (!isSc()) {
            return false;
        }
        for (int i = 0; i < V; i++) {
            if (list.get(i).size() != count[i]) {
                return false;
            }
        }
        return true;
    }

    public boolean isSc() {
        boolean[] visited = new boolean[V];
        for (int i = 0; i < V; i++) {
            visited[i] = false;
        }
        int i = 0;
        int start = 0;
        for (i = 0; i < V; i++) {
            if (list.get(i).size() > 0) {
                start = i;
                break;
            }
        }
        DFS(visited, start);
        for (i = 0; i < V; i++) {
            if (list.get(i).size() > 0 && !visited[i]) {
                return false;
            }
        }

        Graph gr = getTranspose();
        for (i = 0; i < V; i++) {
            visited[i] = false;
        }
        gr.DFS(visited, start);
        for (i = 0; i < V; i++) {
            if (list.get(i).size() > 0 && !visited[i]) {
                return false;
            }
        }
        return true;
    }

    public Graph getTranspose() {
        Graph gr = new Graph(V);
        for (int i = 0; i < V; i++) {
            ArrayList<Integer> temp = list.get(i);
            for (int j = 0; j < temp.size(); j++) {
                gr.addEdge(temp.get(j), i);
            }
        }
        return gr;
    }

    public void DFS(boolean[] visited, int n) {
        visited[n] = true;
        for (int i = 0; i < list.get(n).size(); i++) {
            int node = list.get(n).get(i);
            if (!visited[node]) {
                DFS(visited, node);
            }
        }
    }
}
python
from collections import defaultdict


def dfs(graph, start, visited, stack):
    visited.add(start)
    for node in graph[start]:
        if node not in visited:
            dfs(graph, node, visited, stack)
    stack.append(start)


def reverse_graph(graph):
    edges = []
    for k, val in graph.items():
        for node in val:
            edges.append((k, node))

    rev = defaultdict(list)
    for u, v in edges:
        rev[v].append(u)

    return rev


def dfs_r(graph, start, visited, store):
    visited.add(start)
    store.append(start)
    for node in graph[start]:
        if node not in visited:
            dfs(graph, node, visited, store)


def kosaraju(graph, n):
    visited = set()
    stack = []
    for i in range(n):
        if i not in visited:
            dfs(graph, i, visited, stack)

    rev = reverse_graph(graph)

    visited = set()
    out = []
    while stack:
        node = stack.pop()
        temp = []
        if node not in visited:
            dfs_r(rev, node, visited, temp)
            out.append(temp)

    return out


T = int(input())
for _ in range(T):
    n = int(input())
    arr = input().strip().split(' ')

    if n == 1:
        st = arr[0]
        if st[0] == st[-1]:
            print(1)
        else:
            print(0)
    else:
        graph = defaultdict(list)
        for i in range(n):
            for j in range(n):
                if i == j:
                    continue
                if arr[i][-1] == arr[j][0]:
                    graph[i].append(j)

        scc = kosaraju(graph, n)
        if len(scc) == 1:
            print(1)
        else:
            print(0)

发布了71 篇原创文章 · 获赞 21 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_33935895/article/details/103150054