博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
图的一些算法题2
阅读量:2395 次
发布时间:2019-05-10

本文共 6839 字,大约阅读时间需要 22 分钟。

N couples sit in 2N seats arranged in a row and want to hold hands. We want to know the minimum number of swaps so that every couple is sitting side by side. A swap consists of choosing any two people, then they stand up and switch seats.

The people and seats are represented by an integer from 0 to 2N-1, the couples are numbered in order, the first couple being (0, 1), the second couple being (2, 3), and so on with the last couple being (2N-2, 2N-1).

The couples' initial seating is given by row[i] being the value of the person who is initially sitting in the i-th seat.

思路:

题意大致为:给你N对数,通过一系列swap之后,使得在每对数中,一个数为偶数,另一个数比它大1。求需要的swap的次数。

题目归类为graph,然而直接的解题方法比图的方法更容易想到:用队列的思想,如果队头的一对数满足要求,直接pop,否则找到一个合适的数对,与之swap(可能swap之后两对数都满足要求,也可能只有对头满足要求),计数加一,再pop。代码如下:

class Solution {public:    int minSwapsCouples(vector
& row) { int count = 0; while(!row.empty()) { if(row[0]%2==0 && row[1]==row[0]+1 || row[1]%2==0 && row[0]==row[1]+1) { pop(row, 0); } else { if(row[0]%2 == 0) { int i; for(i = 0; i < row.size(); i++) if(row[i] == row[0]+1) break; swap(1, i, row); pop(row,0); count++; } else { int i; for(i = 0; i < row.size(); i++) if(row[i] == row[0]-1) break; swap(1, i, row); pop(row,0); count++; } } } return count; } void pop(vector
& row, int p) { auto i = row.begin()+p; row.erase(i); row.erase(i); } void swap(int a, int b, vector
& row) { int t = row[a]; row[a] = row[b]; row[b] = t; }};

那么如何用图的思路来做呢?首先将原始的每个数对看做一个结点,如果两个数对通过交换能够使得其中的一个或者两个数对满足条件,结点之间连一条边,最终形成一个无向图。swap的次数即为边的个数减去环的个数。(环中的边数比处理环中的数对需要的次数多一)。

Two strings X and Y are similar if we can swap two letters (in different positions) of X, so that it equals Y.

For example, "tars" and "rats" are similar (swapping at positions 0 and 2), and "rats" and "arts" are similar, but "star" is not similar to "tars""rats", or "arts".

Together, these form two connected groups by similarity: {"tars", "rats", "arts"} and {"star"}.  Notice that "tars" and "arts" are in the same group even though they are not similar.  Formally, each group is such that a word is in the group if and only if it is similar to at least one other word in the group.

思路:每个字符串作为一个结点,如果两个字符串是“相似”的,那么两个结点相连。题目也就是让我们求其中连通图的数量。常规的方法就是构建邻接表,DFS出所有连通图(效率比较低,beat 15),代码如下:

class Solution {public:    int numSimilarGroups(vector
& A) { map
> adj; int size = A.size(); set
s; for(int i = 0; i < size-1; i++) { s.insert(i); for(int j = i+1; j < size; j++) { if(connect(A[i], A[j])) { adj[i].push_back(j); adj[j].push_back(i); } } } s.insert(size-1); int times = 0; while(!s.empty()) { auto t = s.begin(); DFS(*t, s, adj); times++; } return times; } bool connect(string& a, string& b) { int count = 0; for(int i = 0; i < a.length(); i++) if(a[i] != b[i]) count++; return count==2||count==0; } void DFS(int node, set
& s, map
>& adj) { if(s.find(node) == s.end()) return; s.erase(node); for(auto&i:adj[node]) { DFS(i, s, adj); } }};

另外,这一题可以使用并查集(或union-find)来解决问题。

并查集:

  一种数据结构,将一个集合分为不相交的子集,在添加新的子集,合并现有子集,判断元素所在集合时时间复杂度接近常数级。常用于求连通子图和最小生成树的Kruskal算法。

操作:

  makeSet:  初始化,给每个元素分配一个特定的id,以及一个指向自己的指针,表示每个元素都在一个大小为1的集合当中。

  find:       查找某个元素的根元素。当两个元素拥有同样的根元素时,说明他们在同一个集合当中。为了使得时间复杂度接近常数级,在查找的过程中,可以更新指针指向根元素(代码中使用递归方法),有人称其为路径压缩。

  Union:      满足条件则合并两个子集。如果没有特殊要求,将一个集合的根指向另一个集合的根即可。也可根据秩或者集合的大小来指定。

所以对于这一题,我们建立一个并查集,子集的数量就是连通子图的数量,也就是需要的group的数量。效率得到提高(beat 75)

代码如下:

class Solution {public:    int numSimilarGroups(vector
& A) { int size = A.size(); vector
next(size); makeSet(next); int s = size; for(int i = 0; i < s-1; i++) { for(int j = i+1; j < s; j++) { if(connect(A[i], A[j])) { unionSet(i, j, next, size); } } } return size; } bool connect(string& a, string& b) { int count = 0; for(int i = 0; i < a.length(); i++) if(a[i] != b[i]) count++; return count==2||count==0; } void makeSet(vector
& next) { int j = 0; for(auto& i:next) i = j++; } void unionSet(int i, int j, vector
& next, int& size) { int root_i = find(i, next), root_j = find(j, next); if(root_i != root_j) { next[root_i] = root_j; size--; } } int find(int i, vector
& next) { if(i != next[i]) next[i] = find(next[i], next); return next[i]; }};

Strings A and B are K-similar (for some non-negative integer K) if we can swap the positions of two letters in A exactly K times so that the resulting string equals B.

Given two anagrams A and B, return the smallest K for which A and B are K-similar.

思路:尝试使用贪心算法。策略为:替换只在不符合的字母之间进行,如果一次替换使得两个不符合的数同时符合,这个替换优先执行。然而,行不通,只通过了一半的测例。如"aabbccddee" "cdacbeebad"就无法通过。显然,某次替换会对之后的替换产生潜在影响。那……就用DFS把所有情况找出来,找出最小K的方案吧(暴力求解)。代码如下:

class Solution {private:    int size;    int new_size;    int result;public:    int kSimilarity(string A, string B) {        this->size = A.length();        string a, b;        for(int i = 0; i < this->size; i++) {            if(A[i] != B[i]) {                a.push_back(A[i]);                b.push_back(B[i]);            }        }        this->new_size = a.length();        if(this->new_size == 0)            return 0;        this->result = INT_MAX;        DFS(a, b, 0, 0);        return this->result;    }    void DFS(string a, string b, int p, int k) {        if(p == this->new_size-1) {            this->result = min(this->result, k);            return;        }        if(a[p] == b[p]) {            DFS(a, b, p+1, k);            return;        }        for(int j = p+1; j < this->new_size; j++) {            if(a[p] == b[j]) {                swap(b[p], b[j]);                DFS(a, b, p+1, k+1);                swap(b[p], b[j]);            }        }    }    void swap(char& a, char& b) {        char t = a;        a = b;        b = t;    }};

另外,还可以通过存储已经计算过的经过某些交换后的串的K值来避免重复计算,进而提高效率。

转载地址:http://eggab.baihongyu.com/

你可能感兴趣的文章
不可不知的python陷阱
查看>>
进程管理工具--supervisor
查看>>
使用virtualenv在ubuntu上搭建python-3开发环境
查看>>
详解-Python-的-“==”-和-“is”
查看>>
Tensorflow-Python-API-翻译(array_ops)
查看>>
Tensorflow-Python-API-翻译(constant_op)
查看>>
Tensorflow-Python-API-翻译(framework)
查看>>
Tensorflow-Python-API-翻译(math_ops)(第二部分)
查看>>
Tensorflow-Python-API-翻译(math_ops)(第一部分)
查看>>
论文阅读---An-Artificial-Neural-Network-based-Stock-Trading-System-Using-T
查看>>
A-Paper-A-Day--#1-Convolutional-Sequence-to-Sequence-Learning
查看>>
7个很棒的-chatbot-应用场景
查看>>
标记问题:词性标注(POS)和命名实体识别(NER)
查看>>
标记问题:介绍
查看>>
标记问题:生成模型和噪声通道模型
查看>>
机器学习算法在文本分类中的应用综述
查看>>
利用-TensorFlow-构建卷积神经网络
查看>>
利用-TensorFlow-实现排序和搜索算法
查看>>
利用TensorFlow实现卷积神经网络做文本分类
查看>>
如何构建高可读性和高可重用的-TensorFlow-模型
查看>>