目录
题目:输入一个字符串,按字典序打印出该字符串中字符的所有排列。
题目:输入一个含有8个数字的数组,把这8个数字放在正方体的8个顶点上,使得正方体上相对的面上的4个顶点的和都相等。
题目:在一个字符串中找到第一个只出现一次的字符,并返回它的位置。
题目:定义一个函数,输入两个字符串,从第一个字符串中删除在第二个字符串中出现的所有字符。
题目:输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba.
看下图,用回溯法,直观明了。
图片来自牛客网剑指offer中一位网友的回答。
/*
这是一个字符串排列问题,考虑使用回溯法
可以分为两部分来做
第一部分:求所有可能在第一个位置的字符,即把第一个字符与后面所有字符交换,包括自己和自己交换
第二部分:固定第一个字符,求后面所有字符的排列,即又回到第一部分
其中注意一个问题:如果第一个字符与后面某一个位置字符相同,则不用交换
*/
class Solution {
public:
vector<string> Permutation(string str) {
vector<string> all;
if(str.size() == 0){
return all;
}
string tmp;
recur(str, tmp, all, 0);
return all;
}
void recur(string str, string& tmp, vector<string> &all, int start){
if(start < 0 || str.size() == 0){
return;
}
if(str.size() == start){
all.push_back(tmp);
return;
}
for(int i = start; i < str.size(); i++){
if(i != start && str[i] == str[start]){ //如果字符相同,不用交换
continue;
}
swap(str[i], str[start]);
tmp += str[start];
recur(str, tmp, all, start + 1);
tmp.pop_back(); //回溯法的关键
}
}
};
题目:输入一个字符串,求字符的所有组合。例如:输入abc,则它们的组合有a、b、c、ab、ac、bc、abc。其中ab和ba只是一种组合。
/*
输入n个字符,那么形成的组合长度有1、2、... 、n
在n个字符中求长m的字符时,可以分成两部分:第一个字符和其余所有字符
如果组合中包含第一个字符,则在剩余字符中求m-1个字符
如果组合中不包含第一个字符,则在剩余字符中求m个字符
就可以用递归的方法求解
*/
class Solution
{
public:
vector<string> combination(string str){
vector<string> all;
if (str.size() == 0) {
return all;
}
string tmp;
for (int i = 1; i <= str.size(); i++) {
recur(str, tmp, 0, i, all);
}
return all;
}
void recur(string str, string &tmp, int start, int number, vector<string>& all){
if (number == 0) {
all.push_back(tmp);
return;
}
if (start == str.size()) {
return;
}
if (number > str.size() - start) {
return;
}
tmp += str[start];
recur(str, tmp, start + 1, number - 1, all);
tmp.pop_back();
recur(str, tmp, start + 1, number, all);
}
};
题目:输入一个含有8个数字的数组,判断有没有可能把这8个数字分别放在正方体的8个顶点上,使得正方体上三组相对的面上的4个顶点的和都相等。
/*
简而言之,这就是一个全排列问题
把这8个数全排列,之后判断正方体的三个像对面是否相等即可
*/
class Solutin{
public:
bool cubeVertex(vector<int> vec) {
if (vec.size() != 8) {
return false;
}
return cubeCore(vec, 0);
}
bool cubeCore(vector<int>& vec, int start) {
if (vec.size() != 8 || start < 0) {
return false;
}
bool result = false;
if (start == vec.size() - 1) { //判断正方体的三个相对面是否相等
if (Sum(vec, 0, 1, 2, 3) == Sum(vec, 4, 5, 6, 7)
&& Sum(vec, 0, 2, 4, 6) == Sum(vec, 1, 3, 5, 7)
&& Sum(vec, 0, 1, 4, 5) == Sum(vec, 2, 3, 6, 7)) {
result = true;
}
}
else {
for (int i = start; i < vec.size(); i++) {
if (i != start && vec[i] == vec[start]) {
continue;
}
swap(vec[i], vec[start]);
result = cubeCore(vec, start + 1);
if (result) { //一旦为true,则直接break,后面无需在做排序
break;
}
swap(vec[i], vec[start]);
}
}
return result;
}
int Sum(vector<int> vec, int i, int j, int k, int l) {
return vec[i] + vec[j] + vec[k] + vec[l];
}
}
题目:N皇后问题,在一个N*N的棋盘上放置N个皇后,使其不能互相攻击(同一行、同一列、同一斜线上的皇后都会自动攻击),即任意两个皇后不得处于同一行、同一列、同意斜线上。
/*
经典的N皇后问题
假如N=4
我们可以定义一个数组column[4],数组中第i个数字表示位于第i行的皇后的列号
并将0,1,2,3分别放入数组中,放入的时候判断是否在同一列以及是否时一条斜线
它们肯定不会在同一行,因为数组下标0,1,2,3各不相同,因此所在行肯定不同
*/
class Solution{
public:
int totalNQueens(int n) {
if (n < 0) {
return 0;
}
vector<int> vec(n);
int sum = 0;
QueenCore(0, n, vec, sum);
return sum;
}
void QueenCore(int index, int n, vector<int> &vec, int &sum) {
if (index >= n) {
sum++;
}
else {
for (int i = 0; i < n; i++) {
vec[index] = i;
if (Diagonal(vec, index)) { //判断是否在同一列或者是否在一条斜线上
QueenCore(index + 1, n, vec, sum);
}
}
}
}
bool Diagonal(const vector<int> &vec, int index) {
for (int i = 0; i < index; i++) {
if ((abs(vec[i] - vec[index]) == abs(i - index)) || vec[i] == vec[index]) {
return false;
}
}
return true;
}
}
题目:在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写)
/*
char是一次长度为8的数据类型。因此有256中可能。
创建一个大小为256的数组,下标对应ASCII码值,存储的数是出现的次数
*/
int FirstNotRepeatingChar(string str) {
if(str.size() < 0 || str.size() > 10000) {
return -1;
}
int* position = new int[256];
for(int i = 0; i < 256; i++){
position[i] = 0;
}
for(int i = 0; i < str.size(); i++){
position[str[i]]++;
}
for(int i = 0; i < str.size(); i++){
if(position[str[i]] == 1){
return i;
}
}
return -1;
}
题目:定义一个函数,输入两个字符串,从第一个字符串中删除在第二个字符串中出现的所有字符。
void deleteSubstring(string& str1, const string& str2){
if(str1.size() == 0 || str2.size() == 0){
return;
}
bool* map = new bool[256];
for(int i = 0; i < 256; i++){
map[i] = false;
}
for(int i = 0; i < str2.size(); i++){
map[str2[i]] = true;
}
for(int it = str1.begin(); it != str1.end(); it++){
if(map[*it] == true){
str1.erase(it);
}
}
}
题目:定义一个函数,删除字符串中所有重复出现的字符。
void deleteDupstring(string& str){
if(str.size() == 0){
return;
}
bool* map = new bool[256];
for(int i = 0; i < 256; i++){
map[i] = false;
}
for(int it = str.begin(); it != str.end(); it++){
if(map[*it] == true){
str.erase(it);
}
else{
map[*it] = true;
}
}
}
题目:在英语中,如果两个单词出现的字母相同,并且每个字母出现的次数也相同,那么两个单词护卫变位词。定义函数,是否互为变位词。
bool isAnagram(const string& str1, const string& str2){
if(str1.size() == 0 || str2.size() == 0 || str1.size() != str2.size()){
return false;
}
int* map = new int[256];
for(int i = 0; i < 256; i++){
map[i] = 0;
}
for(int i = 0; i < str1.size(); i++){
map[str[i]]++;
}
for(int i = 0; i < str2.size(); i++){
map[str[i]]--;
}
for(int i = 0; i < 256; i++){
if(map[str[i]] != 0){
return false;
}
}
return true;
}
题目:字符流中第一个只出现一次的字符。
// 把字符流的字符一次保存下来
class Solution{
private:
string str;
int count[256];
public:
Solution() {
for(int i = 0; i < 256; i++){
count[i] = 0;
}
}
void insert(char ch){
str += to_string(ch);
count[ch]++;
}
char firstOnce(){
int len = str.size();
for(int i = 0; i < len; i++){
if(count[str[i]] == 1){
return str[i];
}
}
return '#';
}
};
// 不保存字符
class Solution1{
private:
int index;
int count[256];
public:
Solution1() : index(0) {
for(int i = 0; i < 256; i++){
count[i] = -1;
}
}
void inset(char ch){
if(count[ch] == -1){
count[ch] = index;
}
else if(count[ch] >= 0){
count[ch] = -2;
}
index++;
}
char firstOnce(){
char tmp = '\0';
int minIndex = INT_MAX;
for(int i = 0; i < 256; i++){
if(count[i] >= 0 && count[i] < minIndex){
minIndex = count[i];
tmp = char(i);
}
}
return tmp;
}
};
参考
剑指offer