给出两个单词(start和end)与一个字典,找出从start到end的最短转换序列

问题

给出两个单词(start和end)与一个字典,找出从start到end的最短转换序列。规则如下:

  • 一次只能改变一个字母
  • 中间单词必须在字典里存在

例如:

给出

start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]

返回

[

["hit","hot","dot","dog","cog"],

["hit","hot","lot","log","cog"]

]

注意

  • 所有单词的长度一样
  • 所有单词中只有小写字母

初始思路

最直接的想法是从start开始,对每个字母位置从‘a‘到‘z‘尝试替换。如果替换字母后的单词在字典中,将其加入路径,然后以新单词为起点进行递归调用,否则继续循环。每层递归函数终止的条件是end出现或者单词长度*26次循环完毕。end出现时表示找到一个序列,对比当前最短序列做相应更新即可。

处理过程中需要注意的主要有几点:

  • 不能相同字母替换,如hot第一个位置遍历到h时不应该处理。否则就会不断的在hot上死循环。因此在替换后前要做一次检查。
  • 我们要找的是最短的转换方案,所以转换序列不应该出现重复的单词。否则组合将会有无数多种,如例子中的["hit","hot","dot","dog","dot","dog","dog",....."cog"]。这里我们可以使用一个unordered_set容器来保存某次一次替换序列中已出现过的单词,也可以每次使用std:find去搜索当前替换序列。如果使用unordered_set,在递归处理时,和单词序列一样,要在递归后做相应的出栈操作。
  • 处理过程中如果发现当前处理序列长度已经超过当前最短序列长度,可以中止对该序列的处理,因为我们要找的是最短的序列。

  

  1 class Solution {
  2 public:
  3     std::vector<std::vector<std::string>> findLadders(std::string start, std::string end, std::unordered_set<std::string> &dict)
  4     {
  5         std::vector<std::vector<std::string>> result;
  6         std::vector<std::string> entry;
  7
  8         entry.push_back(start);
  9         Find(start, end, dict, 0, result, entry);
 10
 11         return result;
 12     }
 13
 14 private:
 15     void Find(std::string& start, const std::string& end, const std::unordered_set<std::string> &dict
 16               , size_t positionToChange, std::vector<std::vector<std::string>>& result, std::vector<std::string>& entry)
 17     {
 18         //如果长度已经等于当前结果中的长度,再找出来肯定就
 19                 //超过了,终止处理
 20         if(!result.empty() && entry.size() == result[0].size())
 21         {
 22             return;
 23         }
 24
 25         for(size_t pos = positionToChange; pos < start.size(); ++pos)
 26         {
 27             char beforeChange = ‘ ‘;
 28             for(int i = ‘a‘; i <= ‘z‘; ++i)
 29             {
 30                                 //防止同字母替换
 31                 if(start[pos] == i)
 32                 {
 33                     continue;
 34                 }
 35                 beforeChange = start[pos];
 36                 start[pos] = i;
 37
 38                 //用std::find的话
 39                 /*
 40                  if(std::find(entry.begin(), entry.end(), start) != entry.end())
 41                  {
 42                       start[pos] = beforeChange;
 43                       continue;
 44                  }
 45                  */
 46                                 //如果单词已经用过的情况
 47                 if(!used_.empty() && used_.count(start)!=0 )
 48                                 {
 49                                       start[pos] = beforeChange;
 50                           continue;
 51                                 }
 52
 53
 54                 if(start == end)
 55                 {
 56                     entry.push_back(start);
 57
 58                                         //只需要保存最短的序列
 59                     if(!result.empty())
 60                     {
 61                         if(entry.size() < result[0].size())
 62                         {
 63                             result.clear();
 64                             result.push_back(entry);
 65                         }
 66                         else if(entry.size() == result[0].size())
 67                         {
 68                             result.push_back(entry);
 69                         }
 70                     }
 71                     else
 72                     {
 73                         result.push_back(entry);
 74                     }
 75                     //完成一个序列,把前面加入的end弹出
 76                     entry.pop_back();
 77                     return;
 78                 }
 79
 80                 if(dict.find(start) != dict.end())
 81                 {
 82                     entry.push_back(start);
 83                     used_.insert(start);
 84                     Find(start, end, dict, 0, result, entry);
 85                     used_.erase(*entry.rbegin());
 86                     entry.pop_back();
 87
 88
 89                     if(!entry.empty())
 90                     {
 91                         start = *entry.rbegin();
 92                     }
 93                     else
 94                     {
 95                         start[pos] = beforeChange;
 96                     }
 97                 }
 98                 else
 99                 {
100                     start[pos] = beforeChange;
101                 }
102             }
103         }
104
105         return;
106     }
107
108     std::unordered_set<std::string> used_;
109 };
110
111 递归实现

提交测试,Judge Small没有问题。Judge Large不幸超时。

优化

观察我们的处理方法,找到可变换后的单词后,我们会马上基于它继续查找。这是一种深度优先的查找方法,即英文的DFS(Depth-first search)。这对找出答案很可能是不利的,如果一开始进入了一条很长的序列,就会浪费了时间。而广度优先BFS(Breadth-first search)的方法似乎更合适,当找到一个序列时,这个序列肯定是最短的之一。

要进行广度优先遍历,我们可以在发现替换字母后的单词在字典中时,不马上继续处理它,而是将其放入一个队列中。通过队列先进先出的性质,就可以实现广度优先的处理了。由于最后要输出的是整个转换序列,为了简单起见,我们可以将当前已转换出的序列放入队列中,即队列形式为std::vector<std::vector<std::string>>,序列的最后一个元素就是下次处理时要继续转换的单词。

使用广度优先遍历后,还有一个特性使得我们可以更方便的处理深度优先中重复单词的问题。当一个单词在某一层(一层即从第一个单词到当前单词的长度一样的序列)出现后,后面再出现的情况肯定不会是最短序列(相当于走了回头路),因此我们可以在处理完一层后直接将已用过的单词从字典中去除。需要注意的是,同一层是不能去除的,如例子中的hot在两个序列的第二层中都出现了。这样我们就需要一个容器把当前层用过的单词保存起来,等处理的层数发生变化时再将它们从字典里移除。

最后要注意的是查找结束的条件。由于找到了一个序列后该序列只是最短的之一,我们还要继续进行处理,直到队列中当前层都处理完毕。所以我们要在找到一个序列后将它的长度记录下来,当要处理的序列长度已经大于该值时,就可以结束查找了。

 1 class Solution {
 2 public:
 3     std::vector<std::vector<std::string> > findLadders(std::string start, std::string end, std::unordered_set<std::string> &dict)
 4     {
 5         std::queue<std::vector<std::string>> candidate;
 6
 7         std::vector<std::vector<std::string>> result;
 8         std::unordered_set<std::string> usedWord;
 9
10         std::string currentString;
11         bool foundShortest = false;
12         size_t shortest = 0;
13         size_t previousPathLen = 0;
14
15         candidate.push({start});
16
17         while(!candidate.empty())
18         {
19             currentString = *candidate.front().rbegin();
20
21             if(candidate.front().size() != previousPathLen)
22             {
23                 for(auto iter = usedWord.begin(); iter != usedWord.end(); ++iter)
24                 {
25                     dict.erase(*iter);
26                 }
27             }
28
29             if(foundShortest && candidate.front().size() >= shortest)
30             {
31                 break;
32             }
33
34             for(size_t pos = 0; pos < start.size(); ++pos)
35             {
36                 char beforeChange = ‘ ‘;
37                 for(int i = ‘a‘; i <= ‘z‘; ++i)
38                 {
39                     beforeChange = currentString[pos];
40
41                     if(beforeChange == i)
42                     {
43                         continue;
44                     }
45
46                     currentString[pos] = i;
47
48                     if(dict.count(currentString) > 0)
49                     {
50                         usedWord.insert(currentString);
51
52                         if(currentString == end)
53                         {
54                             result.push_back(candidate.front());
55                             result.rbegin()->push_back(end);
56                             foundShortest = true;
57                             shortest = result.rbegin()->size();
58                         }
59                         else
60                         {
61                             std::vector<std::string> newPath(candidate.front());
62                             newPath.push_back(currentString);
63
64                             candidate.push(newPath);
65                         }
66                     }
67                     currentString[pos] = beforeChange;
68                 }
69             }
70
71             if(!candidate.empty())
72             {
73                 previousPathLen = candidate.front().size();
74
75                 candidate.pop();
76             }
77         }
78
79         return result;
80     }
81 };
82
83 BFS实现1

提交后Judge Large多处理了几条用例,但是最后还是超时了。

再次优化

一个比较明显的优化点是我们把存储序列的vector放到了队列中,每次都要拷贝旧队列然后产生新队列。回想一下我们使用vector的原因,主要是为了能保存序列,同时还能获得当前序列的长度。为了实现这两个目的,我们可以定义如下结构体:

 1 struct PathTag
 2 {
 3     PathTag* parent_;
 4     std::string value_;
 5     int length_;
 6
 7     PathTag(PathTag* parent, const std::string& value, int length) : parent_(parent), value_(value), length_(length)
 8     {
 9     }
10 };

结构体记录了当前单词的前一个单词以及当前的序列长度。有了这个结构体,我们在最后找到end后就可以通过不断往前回溯得出整个路径。而这个路径是反向的,最后还需要做一次倒置操作。改进前面的BFS代码如下(需要注意的是,由于LeetCode里不能使用智能指针,我们通过辅助函数来申请和释放裸指针而不是直接new。如果不关心内存问题的话直接new了不管也可。):

  1 class Solution{
  2 public:
  3     ~Solution()
  4     {
  5         for(auto iter = pool_.begin(); iter != pool_.end(); ++iter)
  6         {
  7             delete *iter;
  8         }
  9     }
 10
 11     std::vector<std::vector<std::string> > findLadders(std::string start, std::string end, std::unordered_set<std::string> &dict)
 12     {
 13                 std::queue<PathTag*> candidate;
 14
 15         std::vector<std::vector<std::string>> result;
 16         std::unordered_set<std::string> usedWord;
 17
 18         std::string currentString;
 19         bool foundShortest = false;
 20         size_t shortest = 0;
 21         size_t previousPathLen = 0;
 22
 23         candidate.push(AllocatePathTag(nullptr, start, 1));
 24
 25         while(!candidate.empty())
 26         {
 27             PathTag* current = candidate.front();
 28             currentString = current->value_;
 29
 30             if(current->length_ != previousPathLen)
 31             {
 32                 for(auto iter = usedWord.begin(); iter != usedWord.end(); ++iter)
 33                 {
 34                     dict.erase(*iter);
 35                 }
 36             }
 37
 38             if(foundShortest && current->length_ >= shortest)
 39             {
 40                 break;
 41             }
 42
 43
 44             for(size_t pos = 0; pos < start.size(); ++pos)
 45             {
 46                 char beforeChange = ‘ ‘;
 47                 for(int i = ‘a‘; i <= ‘z‘; ++i)
 48                 {
 49                     beforeChange = currentString[pos];
 50
 51                     if(beforeChange == i)
 52                     {
 53                         continue;
 54                     }
 55
 56                     currentString[pos] = i;
 57
 58                     if(dict.count(currentString) > 0)
 59                     {
 60                         usedWord.insert(currentString);
 61
 62                         if(currentString == end)
 63                         {
 64
 65                             GeneratePath(result, current, currentString);
 66                             foundShortest = true;
 67                             shortest = result.rbegin()->size();
 68                             continue;
 69                         }
 70                         else
 71                         {
 72                             candidate.push(AllocatePathTag(current, currentString, current->length_ + 1));
 73                         }
 74                     }
 75                     currentString[pos] = beforeChange;
 76                 }
 77             }
 78
 79             if(!candidate.empty())
 80             {
 81                 previousPathLen = current->length_;
 82
 83                 candidate.pop();
 84             }
 85         }
 86
 87         return result;
 88     }
 89
 90 private:
 91     struct PathTag
 92     {
 93         PathTag* parent_;
 94         std::string value_;
 95         int length_;
 96
 97         PathTag(PathTag* parent, const std::string& value, int length) : parent_(parent), value_(value), length_(length)
 98         {
 99
100         }
101
102     };
103
104     PathTag* AllocatePathTag(PathTag* parent, const std::string& value, int length)
105     {
106         if(nextPoolPos_ >= pool_.size())
107         {
108             for(int i = 0; i < 100; ++i)
109             {
110                 PathTag* newTag = new PathTag(nullptr, " ", 0);
111                 pool_.push_back(newTag);
112             }
113         }
114
115         PathTag* toReturn = pool_[nextPoolPos_];
116         toReturn->parent_ = parent;
117         toReturn->value_ = value;
118         toReturn->length_ = length;
119
120         ++nextPoolPos_;
121
122         return toReturn;
123     }
124
125     int nextPoolPos_;
126
127     std::vector<PathTag*> pool_;
128
129     void GeneratePath(std::vector<std::vector<std::string>>& result, PathTag* pathTag, const std::string& end)
130     {
131         std::vector<std::string> path;
132
133         path.push_back(end);
134
135         while(pathTag != nullptr)
136         {
137             path.push_back(pathTag->value_);
138
139             pathTag = pathTag->parent_;
140         }
141
142         size_t left = 0;
143         size_t right = path.size() - 1;
144
145         while(left < right)
146         {
147             std::swap(path[left], path[right]);
148
149             ++left;
150             --right;
151         }
152
153         result.push_back(path);
154     }
155
156 };
157
158 BFS2

提交后Judge Large又多处理了几条用例,但是还是没能通过。

使用邻接列表

在继续优化之前,我们先来学习一个图论中的概念 - 邻接列表(Adjacency List)。具体细节可以参见这篇wiki:http://en.wikipedia.org/wiki/Adjacency_list 。简单来说,这是一个存储图中每个顶点的所有邻接顶点的数据结构。如无向图:

a

/       \

b    ---    c

它的邻接列表为:

a => b, c

b => a, c

c => a, b

具体到本问题,我们可以发现,start到end的所有序列,就是一个这些序列中所有单词为点组成的图。如果我们生成了该图的邻接列表,就可以不断的在每个单词的邻接列表里找到转换的下一个单词,从而最终找到end。那么,我们首先要对字典里的单词生成邻接列表:遍历字典里的单词,针对每个单词用前面逐字母替换的方法找出邻接单词,并保存起来。这里使用一个std::unordered_map<std::string, std::unordered_set<std::string>>来保存邻接列表。

有了邻接列表,寻找序列的方法就发生变化了。我们不再逐个替换字母,而是从start出发,遍历start的邻接顶点,将邻接顶点放入队列中。并重复操作直到队列为空。还有一个发生变化的地方是去重操作。由于不再遍历字典,现在我们发现非同层出现重复的单词就跳过它而不是从字典里删去。

剩下的生成路径的方法仍然和BFS2类似,全部代码如下:

  1 class Solution {
  2 public:
  3     ~Solution()
  4     {
  5         for(auto iter = pool_.begin(); iter != pool_.end(); ++iter)
  6         {
  7             delete *iter;
  8         }
  9     }
 10
 11     std::vector<std::vector<std::string> > findLadders(std::string start, std::string end, std::unordered_set<std::string> &dict)
 12     {
 13         nextPoolPos_ = 0;
 14         std::unordered_map<std::string, std::unordered_set<std::string>> adjacencyList;
 15         std::string word;
 16
 17         for (auto iter = dict.begin(); iter != dict.end(); ++iter)
 18         {
 19             word = *iter;
 20             BuildAdjacencyList(word, adjacencyList, dict);
 21         }
 22
 23         std::vector<std::vector<std::string>> result;
 24         std::queue<PathTag*> candidate;
 25         std::unordered_map<std::string, int> usedWord;
 26
 27         std::string currentString;
 28         bool foundShortest = false;
 29         size_t shortest = 0;
 30
 31         candidate.push(AllocatePathTag(nullptr, start, 1));
 32
 33         while(!candidate.empty())
 34         {
 35             PathTag* current = candidate.front();
 36
 37             if(foundShortest && current->length_ >= shortest)
 38             {
 39                 break;
 40             }
 41
 42             candidate.pop();
 43
 44             auto adjacentIter = adjacencyList.find(current->value_);
 45
 46             if(adjacentIter != adjacencyList.end())
 47             {
 48                 for(auto iter = adjacentIter->second.begin(); iter != adjacentIter->second.end(); ++iter)
 49                 {
 50                     if(*iter == end)
 51                     {
 52                         GeneratePath(result, current, *iter);
 53                         foundShortest = true;
 54                         shortest = result.rbegin()->size();
 55                         continue;
 56                     }
 57
 58                     auto usedIter = usedWord.find(*iter);
 59
 60
 61                     if(usedIter != usedWord.end() && usedIter->second != current->length_ + 1)
 62                     {
 63                         continue;
 64                     }
 65
 66                     usedWord[*iter] = current->length_ + 1;
 67
 68                    candidate.push(AllocatePathTag(current, *iter, current->length_ + 1));
 69                 }
 70             }
 71             else
 72             {
 73                 continue;
 74             }
 75
 76         }
 77
 78         return result;
 79     }
 80
 81 private:
 82     struct PathTag
 83     {
 84         PathTag* parent_;
 85         std::string value_;
 86         int length_;
 87
 88         PathTag(PathTag* parent, const std::string& value, int length) : parent_(parent), value_(value), length_(length)
 89         {
 90         }
 91
 92     };
 93
 94     PathTag* AllocatePathTag(PathTag* parent, const std::string& value, int length)
 95     {
 96         if(nextPoolPos_ >= pool_.size())
 97         {
 98             for(int i = 0; i < 100; ++i)
 99             {
100                 PathTag* newTag = new PathTag(nullptr, " ", 0);
101                 pool_.push_back(newTag);
102             }
103         }
104
105         PathTag* toReturn = pool_[nextPoolPos_];
106         toReturn->parent_ = parent;
107         toReturn->value_ = value;
108         toReturn->length_ = length;
109
110         ++nextPoolPos_;
111
112         return toReturn;
113     }
114
115     int nextPoolPos_;
116
117     std::vector<PathTag*> pool_;
118
119     void GeneratePath(std::vector<std::vector<std::string>>& result, PathTag* pathTag, const std::string& end)
120     {
121         std::vector<std::string> path;
122
123         path.push_back(end);
124
125         while(pathTag != nullptr)
126         {
127                         path.push_back(pathTag->value_);
128
129             pathTag = pathTag->parent_;
130                 }
131
132         size_t left = 0;
133         size_t right = path.size() - 1;
134
135         while(left < right)
136         {
137             std::swap(path[left], path[right]);
138
139             ++left;
140             --right;
141         }
142
143         result.push_back(path);
144     }
145
146     void BuildAdjacencyList(std::string& word, std::unordered_map<std::string, std::unordered_set<std::string>>& adjacencyList, const std::unordered_set<std::string>& dict)
147     {
148         std::string original = word;
149
150         for(size_t pos = 0; pos < word.size(); ++pos)
151         {
152             char beforeChange = ‘ ‘;
153             for(int i = ‘a‘; i <= ‘z‘; ++i)
154             {
155                 beforeChange = word[pos];
156
157                 if(beforeChange == i)
158                 {
159                     continue;
160                 }
161
162                 word[pos] = i;
163
164                 if(dict.count(word) > 0)
165                 {
166                     auto iter = adjacencyList.find(original);
167                     if(iter != adjacencyList.end())
168                     {
169                         iter->second.insert(word);
170                     }
171                     else
172                     {
173                         adjacencyList.insert(std::pair<std::string, std::unordered_set<std::string>>(original, std::unordered_set<std::string>()));
174                         adjacencyList[original].insert(word);
175                     }
176                 }
177
178                 word[pos] = beforeChange;
179             }
180         }
181
182     }
183 };
184
185 邻接列表BFS

这回终于通过Judge Large了。

一种更快的解决方案

下面再介绍一种更快的解决方案,思路及代码来自niaokedaoren的博客

前一个解决方案虽然能通过大数据集测试,但是为了保存路径信息我们额外引入了一个结构体而且因为需要用到指针使用了大量的new操作。还有什么不用保存所有路径信息的办法?

niaokedaoren的方案中使用了一个前驱单词表,即记录每一个单词的前驱单词是哪些。这样在遍历完毕后,我们从end出发递归就能把所有路径生成出来。但是由于前驱单词表不能记录当前的层次信息,似乎我们没法完成去重的工作。这个方案的巧妙之处就在于它没有使用我们通常的队列保存待处理的单词,一个单词一个单词先进先出处理的方法,而是使用两个vector来模拟队列的操作。我们从vector 1中遍历单词进行转换尝试,发现能转换的单词后将其放入vector 2中。当vector 1中的单词处理完毕后即为一层处理完毕,它里面的单词就可以从字典里删去了。接着我们对vector 2进行同样处理,如此反复直到当前处理的vector中不再有单词。我们发现vector 1和vector 2在不断地交换正处理容器和待处理容器的身份,因此可以通过将其放入一个数组中,每次循环对数组下标值取反实现身份的交替:

int current = 0;
int previous = 1;

循环

current = !current;
previous = !previous;......循环结束

完全代码如下:

 1 class Solution {
 2 public:
 3     std::vector<std::vector<std::string> > findLadders(std::string start, std::string end, std::unordered_set<std::string> &dict)
 4     {
 5
 6         result_.clear();
 7         std::unordered_map<std::string, std::vector<std::string>> prevMap;
 8
 9         for(auto iter = dict.begin(); iter != dict.end(); ++iter)
10         {
11             prevMap[*iter] = std::vector<std::string>();
12         }
13
14         std::vector<std::unordered_set<std::string>> candidates(2);
15
16         int current = 0;
17         int previous = 1;
18
19         candidates[current].insert(start);
20
21         while(true)
22         {
23             current = !current;
24             previous = !previous;
25
26             for (auto iter = candidates[previous].begin(); iter != candidates[previous].end(); ++iter)
27             {
28                 dict.erase(*iter);
29             }
30
31             candidates[current].clear();
32
33             for(auto iter = candidates[previous].begin(); iter != candidates[previous].end(); ++iter)
34             {
35                 for(size_t pos = 0; pos < iter->size(); ++pos)
36                 {
37                     std::string word = *iter;
38                     for(int i = ‘a‘; i <= ‘z‘; ++i)
39                     {
40                         if(word[pos] == i)
41                         {
42                             continue;
43                         }
44
45                         word[pos] = i;
46
47                         if(dict.count(word) > 0)
48                         {
49                             prevMap[word].push_back(*iter);
50                             candidates[current].insert(word);
51                         }
52                     }
53                 }
54             }
55
56             if (candidates[current].size() == 0)
57             {
58                 return result_;
59             }
60             if (candidates[current].count(end))
61             {
62                 break;
63             }
64         }
65
66
67         std::vector<std::string> path;
68         GeneratePath(prevMap, path, end);
69
70         return result_;
71     }
72
73 private:
74     void GeneratePath(std::unordered_map<std::string, std::vector<std::string>> &prevMap, std::vector<std::string>& path,
75                       const std::string& word)
76     {
77         if (prevMap[word].size() == 0)
78         {
79             path.push_back(word);
80             std::vector<std::string> curPath = path;
81             reverse(curPath.begin(), curPath.end());
82             result_.push_back(curPath);
83             path.pop_back();
84             return;
85         }
86
87         path.push_back(word);
88         for (auto iter = prevMap[word].begin(); iter != prevMap[word].end(); ++iter)
89         {
90             GeneratePath(prevMap, path, *iter);
91         }
92         path.pop_back();
93     }
94
95     std::vector<std::vector<std::string>> result_;
96 };
97
98 niaokedaoren的方案

可以看到处理速度快了不少:

时间: 2024-10-24 22:21:46

给出两个单词(start和end)与一个字典,找出从start到end的最短转换序列的相关文章

给出2n+1个数,其中有2n个数出现过两次,如何用最简便的方法找出里面只出现了一次的那个数(转载)

有2n+1个数,其中有2n个数出现过两次,找出其中只出现一次的数 例如这样一组数3,3,1,2,4,2,5,5,4,其中只有1出现了1次,其他都是出现了2次,如何找出其中的1? 最简便的方法是使用异或,代码如下: public class XOR { public static void main(String[] args){ int[] arr={3,3,1,2,4,2,5,5,4}; int res=0;//初始值 for(int i=0;i<arr.length;i++){ res ^=

编写一个程序找出100~999之间所有的水仙花数

如果一个3位数等于其各位的立方和,称该数为水仙花数. 如,所以407是一个水仙花数,编写一个程序找出100~999之间所有的水仙花数. 1 #include<stdio.h> 2 #include<stdlib.h> 3 //判断水仙花数,是则返回1 4 int isNarcissus(int n); 5 6 int main() 7 { 8 int i; 9 for(i = 100; i < 1000; i++) 10 if(isNarcissus(i)) 11 print

使用一个函数找出一个整型数组中的最大值和最小值

/***************************************************** 知识点:bool类型,命名空间,输入输出 题目要求: 使用一个函数找出一个整型数组中的最大值和最小值 *****************************************************/ #include<stdlib.h> #include<iostream> using namespace std; namespace CJJ // 定义命名空间

在字符串中找出连续最长的数字串 在字符串中找出连续最长的数字串,并把这个串的长度返回

写一个函数,它的原形是int continumax(char *outputstr,char *intputstr)功能:在字符串中找出连续最长的数字串,并把这个串的长度返回,并把这个最长数字串付给其中一个函数参数outputstr所指内存.例如:"abcd12345ed125ss123456789"的首地址传给intputstr后,函数将返回9, #include<iostream> using namespace std; int ContinueMax(char *

判断两个单向链表是否有相交,并找出交点。

分析: 若相交,则两个链表呈Y型,最后一个结点肯定相同:找交点,则用长的链表减去短的,从与短的链表长度想等处开始,两个链表每次移动一个结点,直到相交则是交点. 代码: NODE* FindNode(NODE* pHead1, NODE* pHead2) { NODE* p1 = pHead1; NODE* p2 = pHead2; int i = 1, j = 1, k = 0, f = 0; if(pHead2 == NULL || pHead2 == NULL) { return NULL;

说出两种一笔调度的算法,并说出这两种移臂调度算法的定义。

1.  最短寻道时间优先算法 最短寻找时间优先算法总是等待访问者挑选寻找时间最短的那个请求先执行. 2.  扫描算法 扫描算法SCAN又称电梯调度算法,SCAN算法是磁头前进方向上最短查找时间优先算法.

在一个数组里面,除了一个数是只有一个之外,其他都是有两个的,编写一个方法找出这唯一的一个数

1 public class singleNum { 2 /* 3 * 因为a^b^a=b,所以1^2^2^3^3=1 4 * 5 * */ 6 7 public int single(int A[]) 8 { 9 int aim,i; 10 for(aim=0,i=0;i<A.length;i++) 11 { 12 aim=aim^A[i]; 13 } 14 return aim; 15 } 16 17 public static void main(String[] args) 18 { 1

c++ 一个有十个整数元素的数组(17 85 67 83 65 49 26 92 38 42),编写一个程序找出其中的最大数和其下标,并在主函数中打印最大数和相应下标

// 5-1 找数组最大值及下标#include<iostream> using namespace std; int main() { int a[10]={17,85,67,83,49,26,92,38,42}; int max,num=0; max=a[0]; for(int i=0;i<10;i++){ if( a[i]>max){ max=a[i]; num=i; } } cout<<"最大值为:"<<max<<&q

(算法)两个单词的最短距离

题目: 有个内含单词的超大文本,给定任意两个单词,找出这个文件中两个单词的最短距离. 思路: 通过两个两个变量来记录两个单词最后出现的位置,然后每次计算两者的距离,并更新最小距离. 假设需要重复查找任意两个单词的最短距离,则需要构造一个散列表,记录每个单词及其出现的位置.当查找某两个单词的最短距离时,只需找出该两单词所在列表差值最小的位置. 查找方法:可以将两个有序列表合并(列表元素包含位置及其所属单词,可以构造结构体). 代码: #include<iostream> #include<