LouZhang

导航

9.15开始

1.

写一个程序, 要求功能:求出用1,2,5这三个数不同个数组合的和为100的组合个数。

如:100个1是一个组合,5个1加19个5是一个组合。。。。 请用C++语言写。

解决方案:

普通方法大家都会:

int main(){
    int cnt = 0;
    for(int i = 0; i <= 100; i ++){
        for(int j = 0; j <= 50; j ++){
            for(int k = 0; k <= 20; k ++){
                if(i + 2 * j + 5 * k == 100)
                    cnt ++;
            }
        }
    }
    printf("%d\n", cnt);
    return 0;
}
View Code

但是这循环是101*51*21次,复杂度大

由题知:假设X为1的个数,Y为2的个数,Z为5的个数,那么满足X+2*Y+5*Z = 100

所以X+5*Z = 100 - 2*Y,很明显X+5*Z是一个偶数,并且Z是<=20的,那么对Z做循环

Z=0, X=100,98,...,0

Z=1,X=95,93,...,1

Z=2,X=90,88,...0

.

.

.

Z=19,X=5,3,1

Z=20,X=0

所以结果只要求出100以内的偶数,95以内的奇数...最后是5以内的奇数再加一次就行了

对于一个奇数N求0到N之间的奇数个数为N/2+1,同样的偶数个数为N/2+1

代码如下:

int main(){
    int sum = 0;
    for(int i = 0; i <= 100; i += 5){
        sum += (100 - i) / 2 + 1;
    }
    printf("%d\n", sum);
    return 0;
}
View Code

 

2.

写一个链表,删除一个结构体中指定的结点

解决方案:

#include <cstdio>
#include <cstring>
#include <cstdlib>


struct stu{
    int age;
    stu *next;
}*list;
struct stu *creatlist(int n){
    stu *h, *p, *s;
    h = new stu;
    h->next = NULL;
    p = h;
    for(int i = 0; i < n; i ++){
        s = new stu;
        p->next = s;
        scanf("%d", &s->age);
        s->next = NULL;
        p = s;
    }
    return h;
}
void output(stu *s){
    s = s->next;
    while(s != NULL){
        printf("%d ", s->age);
        s = s->next;
    }
    puts("");
}
void deletelist(stu *h, int age){
    stu *p = h;
    stu *s = h->next;
    while(s != NULL){
        if(s->age == age){
            p->next = s->next;
            s = s->next;
        }
        else{
            p = p->next;
            s = s->next;
        }        
    }
}
int main(){
    int n;
    scanf("%d", &n);
    stu *s = creatlist(n);
    //output(s->next);
    int age;
    scanf("%d", &age);
    deletelist(s, age);
    output(s);
    return 0;
}
View Code

 

 3.

将二叉树的两个孩子换位置,即左变右,右变左。不能用递规

解决方案:

1)根结点入队列

2)取队首元素并出列,并将该元素左右儿子进行交换

3)如果队列不为空则跳到步骤2

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
using namespace std;


struct tree{
    tree *right;
    tree *left;    
}*list;
void solve(tree *list){
    queue <tree*> Q;
    Q.push(list);
    while(!Q.empty()){
        tree *tmp = Q.front();
        Q.pop();
        swap(tmp->right, tmp->left);
        if(tmp->right != NULL)
            Q.push(tmp->right);
        if(tmp->left != NULL)
            Q.push(tmp->left);
    }
}
View Code

 

 4.

38头牛中选出3头跑得最快的,使用一个每次只能供6头比赛的场地,要求用最快的方法

解决方案:

38只取6只一组,6*6,取前3名,得3*6+2=20,用了6次

20只取5只一组,取前3名,得到3*4=12,用了4次

12只分两组取前3名,得3*2=6,用了2次

最后再加1次

累计13次

 

5.

n1开始,每个操作可以选择对n1或者对n加倍。若想获得整数2013,最少需要多少个操作

解决方案:

直接进行计算,奇数减1除2,偶数直接除以2,2013>1006>503>251>125>62>31>15>7>3>1

再反过来计算从1到2013的次数,为18次

 

 6.

如下函数,在32bit系统foo(2^31-3)的值是:

Int foo(int x)
{

Return x&-x;

}

解决方案:

这题是先计算31-3再计算2异或28的,然后进行 x & -x

对于x & -x的含义:返回值为0,表示x=0;返回值为1,表示x为奇数;返回值为其他数,表示x为x与2^64的最大公约数,即二进制中从右到左的第一个1出现的位数

扩展:x & (x-1) 表示x进进制中1的个数,每执行一次x = x&(x-1),会将x用二进制表示时最右边的一个1变为0,因为x-1将会将该位(x用二进制表示时最右边的一个1)变为0

  所以可通过这个求得一个数是不是2的n次方,代码如下

int func(int x)
{
    if( (x&(x-1)) == 0 )
        return 1;
    else
        return 0;
}

int main()
{
    int x = 8;
    printf("%d\n", func(x));
}
View Code

 

 7.

给两个单向链表,求是否有公共节点并求该公共节点,要求使用空间最小算法

解决方案:

将链表A遍历以及链表B遍历,分别保存最后一个节点以及他们长度,若相同再证明有公共节点

如果他们长度相等,依次遍历就行,如果长度不等,将长度长的先遍历|len_a - len_b|(表示绝对值)

如图

 

 

 9.

static静态在申请的时候不分配内存

struct A{
    A() {}
    ~A() {}
    int m1;
    int m2;
};
struct B{
    B() {}
    ~B() {}
    int m1;
    char m2;
    static char m3;
};
struct C{
    C() {}
    virtual~C() {}
    int m1;
    short m2;
};

int main(){
    printf("%d %d %d\n", sizeof A, sizeof B, sizeof C);
    return 0;
}
View Code

输出的是:8 8 12

 

 10.

定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。要求函数minpush以及pop的时间复杂度都是O(1)

解决方案:这题难点在于pop一个元素之后,怎样确定栈中的最小元素,然后查找就要遍历显示不行,

那么就设定一个辅助栈,将每次数据栈中最小的元素依次入栈,见代码(考虑整型)

#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;


class Stack
{
public:
    void push(int num){
        data_stack.push(num);
        if(!min_stack.size())
            min_stack.push(num);
        else
            if(num <= min_stack.top())
                min_stack.push(num);
    }
    void pop(){
        if(data_stack.top() == min_stack.top())
            min_stack.pop();
        data_stack.pop();
    }
    void output(){
        printf("%d\n", min_stack.top());
    }
protected:
private:
    stack <int > data_stack;
    stack <int > min_stack;
};

int main(){
    Stack s;
    s.push(3);
    s.output();
    s.push(4);
    s.output();
    s.push(2);
    s.output();
    s.push(1);
    s.output();
    s.pop();
    s.output();
    s.pop();
    s.output();
    s.push(0);
    s.output();
    return 0;
}
View Code

 

 11.

求最大子和段

解决方案:从第一个数开始加,如果碰到和为负数则置0,否则和max值比较取最大值

#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;


int a[8] = {1, -2, 3, 10, -4, 7, 2, -5};
int main(){
    int sum = a[0], max = a[0];
    for(int i = 1; i < 8; i ++){
        if(sum + a[i] < 0) sum = 0;
        else sum += a[i];
        if(max < sum)
            max = sum;
    }
    printf("%d\n", max);
    return 0;
}
View Code

 

 12.

查找最小的k个元素

解决方案:

朴素方案或者遍历选择最小K个或者快速排序选择前K个,复杂度略高

可以先插入K个到数组中,然后每插入一个数和前K个比较,比最大的小才插入并删除最大的

如何做到在K个当中查找最大的,可以用一个最大堆,或者用第10题两个栈的做法(个人认为可以,只是弹栈的要换一种方式了)

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
using namespace std;


multiset <int > m;
int main(){
    m.clear();
    m.insert(3);
    m.insert(5);
    m.insert(4);
    m.insert(1);
    m.insert(7);
    m.insert(8);
    m.insert(2);
    m.insert(6);
    for(multiset<int > :: iterator it= m.begin(); it != m.end(); it ++){
        cout<<*it<<endl;
    }
    return 0;
}
code1

参考别人的

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
using namespace std;

const int k = 5;
const int maxn = 1000;
int max_heap[k + 1];
int ed, maxpos;

void insert_min_heap(int data){
    int child = 0;
    if(ed == k + 1){
        if(data >= max_heap[1])
            return;
        max_heap[1] = data;
        for(int i = 1; i * 2 <= k; i = child){
            child = 2 * i;
            if((i * 2 + 1 <= k && max_heap[i*2] < max_heap[i*2+1])){
                child ++;
            }
            if(max_heap[i] < max_heap[child])
                swap(max_heap[i], max_heap[child]);
            else
                break;
        }
        return;
    }
    max_heap[ed ++] = data;
    for(int i = ed - 1; i > 1; i /= 2){
        if(max_heap[i] > max_heap[i/2])
            swap(max_heap[i], max_heap[i/2]);
        else
            break;
    }
}
int main(){
    int n, data;
    ed = 1;
    while(~scanf("%d", &data)){
        insert_min_heap(data);
    }
    for(int i = 1; i <= k; i ++)
        printf("%d ", max_heap[i]);
    puts("");

    return 0;
}
code2

 

 13.

写一个堆排序

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
using namespace std;

int n, a[100];

void init_heap(){
    for(int i = n; i; i --){
        int cur = i;
        while(true){
            int next = -1;
            if((cur * 2 <= n) && (next < 0 || a[cur*2] > a[next]))
                next = cur * 2;
            if((cur * 2 + 1 <= n) && (a[cur*2+1] > a[next]))
                next = cur * 2 + 1;
            if(next < 0 || a[next] <= a[cur])
                break;
            else{
                swap(a[cur], a[next]);
                cur = next;
            }
        }
    }
}
void heap_sort(){
    for(int i = n; i > 1; i --){
        swap(a[1], a[i]);
        int cur = 1;
        while(true){
            int next = -1;
            if((cur * 2 < i) && (next < 0 || a[cur*2] > a[next]))
                next = cur * 2;
            if((cur * 2 + 1 < i) && (a[cur*2+1] > a[next]))
                next = cur * 2 + 1;
            if(next < 0 || a[next] <= a[cur])
                break;
            else{
                swap(a[cur], a[next]);
                cur = next;
            }
        }
    }
}

int main(){
    scanf("%d\n", &n);
    for(int i = 1; i <= n; i ++)
        scanf("%d", a + i);
    init_heap();
    heap_sort();
    for(int i = 1; i <= n; i ++){
        printf("%d%c", a[i], i < n ? ' ' : '\n');
    }
}
View Code

 

 14.

前序中序后序遍历,创建二叉树时采用队列实现层序遍历创建

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;


struct Node{
    int num;
    Node *l, *r;
};
queue <Node * > Q;
void creat_tree(Node *p, int num, int &f){
    Node *s = new Node;
    s->num = num;
    s->l = s->r = NULL;
    if(f == 1){
        p->l = s;
        f = 2;
        Q.push(s);
        return;
    }
    p->r = s;
    f = 1;
    Q.push(s);
    Q.pop();
}
void dlr_output(Node *p){
    if(p == NULL) return;
    printf("%d ", p->num);
    dlr_output(p->l);
    dlr_output(p->r);
}
void ldr_output(Node *p){
    if(p == NULL) return;    
    ldr_output(p->l);
    printf("%d ", p->num);
    ldr_output(p->r);
}
void lrd_output(Node *p){
    if(p == NULL) return;
    lrd_output(p->l);
    lrd_output(p->r);
    printf("%d ", p->num);
}
int main(){
    Node *root = new Node;
    Node *p = new Node;
    int f = 0;
    int num;
    while(!Q.empty()) Q.pop();//清空队列
    while(~scanf("%d", &num)){
        if(f == 0){
            root->num = num;
            root->l = NULL;
            root->r = NULL;
            f = 1;
            p = root;
            Q.push(p);
            continue;
        }
        p = Q.front();
        creat_tree(p, num, f);
    }
    dlr_output(root);puts("");
    ldr_output(root);puts("");
    lrd_output(root);puts("");
    return 0;
}
递归
#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <string>
#include <queue>
using namespace std;


struct TreeNode{
    int value;
    TreeNode *left;
    TreeNode *right;
};
TreeNode *creatTreeNode(int m){
    TreeNode *node = new TreeNode;
    node->value = m;
    node->right = node->left = NULL;
    return node;
}
void DestroyTree(TreeNode *root){
    if(root != NULL){
        TreeNode *l = root->left;
        TreeNode *r = root->right;
        delete root;
        root = NULL;
        DestroyTree(l);
        DestroyTree(r);
    }
}
void connectTree(TreeNode *root, TreeNode *l, TreeNode *r){
    if(root != NULL){
        root->left = l;
        root->right = r;
    }
}
void solve(TreeNode *root);
int main(){
    TreeNode *node1 = creatTreeNode(1);
    TreeNode *node2 = creatTreeNode(2);
    TreeNode *node3 = creatTreeNode(3);
    TreeNode *node4 = creatTreeNode(4);
    TreeNode *node5 = creatTreeNode(5);
    TreeNode *node6 = creatTreeNode(6);
    TreeNode *node7 = creatTreeNode(7);
    connectTree(node1, node2, node3);
    connectTree(node2, node4, node5);
    connectTree(node3, node6, node7);
    solve(node1);
    //DestroyTree(node1);
    return 0;
}

void dlr(TreeNode *root){
    if(!root) return;
    stack <TreeNode* > sta;
    TreeNode *tmp = root;
    while(tmp != NULL || !sta.empty()){        
        while(tmp != NULL){
            printf("%d ", tmp->value);
            sta.push(tmp);
            tmp = tmp->left;
        }
        if(!sta.empty()){
            tmp = sta.top();
            sta.pop();
            tmp = tmp->right;
        }
    }
    puts("");
}
void ldr(TreeNode *root){
    if(!root) return;
    stack <TreeNode* > sta;
    TreeNode *tmp = root;
    while(tmp != NULL || !sta.empty()){
        while(tmp != NULL){
            sta.push(tmp);
            tmp = tmp->left;
        }
        if(!sta.empty()){
            tmp = sta.top();
            sta.pop();
            printf("%d ", tmp->value);
            tmp = tmp->right;
        }
    }
    puts("");
}
void lrd(TreeNode *root){
    if(!root) return;
    stack <TreeNode* > sta;
    TreeNode *cur, *pre = NULL;
    sta.push(root);
    while(!sta.empty()){
        cur = sta.top();
        if( (cur->left == NULL && cur->right ==NULL) ||
            (pre != NULL && (pre == cur->left || pre == cur->right))){
                printf("%d ", cur->value);
                sta.pop();
                pre = cur;
        }else{
            if(cur->right != NULL)
                sta.push(cur->right);
            if(cur->left != NULL)
                sta.push(cur->left);
        }
    }
    puts("");
}
void solve(TreeNode *root){
    dlr(root);
    ldr(root);
    lrd(root);
}
非递归

 

 15.

查找链表中倒数第k个结点

解决方案:

设置两个指针,开始指向头结点,然后第一个移动并计数,当移动了k-1次另一指针开始移动,复杂度为o(n)

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;


struct Node{
    int num;
    Node *next;
};

Node *insert(Node *p, int num){
    Node *s = new Node;
    s->num = num;
    s->next = NULL;
    p->next = s;
    return s;
}
int main(){
    int num;
    Node *root = new Node;
    Node *p = root;
    int k;
    scanf("%d", &k);
    while(~scanf("%d", &num)){
        p = insert(p, num);
    }
    int cnt = 0;
    Node *s1 = root;
    Node *s2 = root;
    while(s1 != NULL){
        cnt ++;
        if(cnt >= k + 1){
            s2 = s2->next;
        }
        s1 = s1->next;
    }
    printf("%d\n", s2->num);
    return 0;
}
View Code

 

 16.

在排序数组中查找和为给定值的两个数字

解决方案:

确定第一个和最后一个的和,假如相加大于给定的数,则较大数前移,小于则较小数后移,相等就输出

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;


int a[100];
int main(){
    int n;
    while(~scanf("%d", &n)){
        for(int i = 0; i < n; i ++)
            scanf("%d", a + i);
        int num;
        scanf("%d", &num);
        int st = 0, ed = n - 1;
        while(true){
            if(a[st] + a[ed] == num){
                printf("%d %d\n", a[st], a[ed]);
                break;
            }else
                if(a[st] + a[ed] > num)
                    ed --;
                else 
                    st ++;
        }
    }
    return 0;
}
View Code

 

 17.

O(logn)Fibonacci数列

解决方案:

(转) 

下面介绍一种时间复杂度是O(logn)的方法。在介绍这种方法之前,先介绍一个数学公式:

{f(n), f(n-1), f(n-1), f(n-2)} ={1, 1, 1,0}n-1

(注:{f(n+1), f(n), f(n), f(n-1)}表示一个矩阵。在矩阵中第一行第一列是f(n+1),第一行第二列是f(n),第二行第一列是f(n),第二行第二列是f(n-1)。)

有了这个公式,要求得f(n),我们只需要求得矩阵{1, 1, 1,0}的n-1次方,因为矩阵{1, 1, 1,0}的n-1次方的结果的第一行第一列就是f(n)。这个数学公式用数学归纳法不难证明。感兴趣的朋友不妨自己证明一下。

现在的问题转换为求矩阵{1, 1, 1, 0}的乘方。如果简单第从0开始循环,n次方将需要n次运算,并不比前面的方法要快。但我们可以考虑乘方的如下性质:

/  an/2*an/2                      n为偶数时
an=
        \  a(n-1)/2*a(n-1)/2            n为奇数时

要求得n次方,我们先求得n/2次方,再把n/2的结果平方一下。如果把求n次方的问题看成一个大问题,把求n/2看成一个较小的问题。这种把大问题分解成一个或多个小问题的思路我们称之为分治法。这样求n次方就只需要logn次运算了。

实现这种方式时,首先需要定义一个2×2的矩阵,并且定义好矩阵的乘法以及乘方运算。当这些运算定义好了之后,剩下的事情就变得非常简单。完整的实现代码如下所示。

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;


struct matrix2by2{
    matrix2by2(
        long long m00 = 0,
        long long m01 = 0,
        long long m10 = 0,
        long long m11 = 0
        )
        :m_00(m00), m_01(m01), m_10(m10), m_11(m11){}

    long long m_00;
    long long m_01;
    long long m_10;
    long long m_11;
};
matrix2by2 matrixmultiply(const matrix2by2 &a, const matrix2by2 &b){
    return matrix2by2(
        a.m_00 * b.m_00 + a.m_01 * b.m_10,
        a.m_00 * b.m_01 + a.m_01 * b.m_11,
        a.m_10 * b.m_00 + a.m_11 * b.m_10,
        a.m_10 * b.m_01 + a.m_11 * b.m_11
        );
}
matrix2by2 matrixpower(int n){
    matrix2by2 matrix;
    if(n == 1)
        matrix = matrix2by2(1, 1, 1, 0);
    else if(n % 2 == 0){
        matrix = matrixpower(n/2);
        matrix = matrixmultiply(matrix, matrix);
    }
    else if(n % 2 == 1){
        matrix = matrixpower((n-1)/2);
        matrix = matrixmultiply(matrix, matrix);
        matrix = matrixmultiply(matrix, matrix2by2(1, 1, 1, 0));
    }
    return matrix;
}
int main(){
    printf("%d\n", matrixpower(10-1).m_00);
    return 0;
}
View Code

 

 18.

定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部。如把字符串abcdef左旋转2位得到字符串cdefab。请实现字符串左旋转的函数。要求时间对长度为n的字符串操作的复杂度为O(n),辅助内存为O(1)

解决方案:

假设这字符串简化为XY,刚分三次操作即可,X旋转,Y旋转,XY旋转

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;


char s[] = "12345";
int n = 5;
int k = 2;

void reversestring(char *st, char *ed){
    while(st < ed){
        char tmp = *st;
        *st = *ed;
        *ed = tmp;

        st ++;
        ed --;
    }
}
int main(){
    char *pst1 = s;
    char *ped1 = s + k - 1;
    char *pst2 = s + k;
    char *ped2 = s + n - 1;
    reversestring(pst1, ped1);
    reversestring(pst2, ped2);
    reversestring(pst1, ped2);
    printf("%s\n", s);
    return 0;
}
View Code

 

 19.

解决方案:从右上角开始查找,如果大就消除该列,如果小就消除该行

(修改)

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;




bool find(int *a, int rows, int cols, int num){
    int row = 0;
    int col = cols - 1;
  //  printf("%d %d %d\n", a[0], num, a[rows * cols - 1]);
    for(int i = 0; i < rows; i ++){
        for(int j = 0; j < cols; j ++){
      //      printf("%d ", a[i * cols + j]);
        }
       // puts("");
    }
    if(a[0] > num || a[rows * cols - 1] < num)
        return false;
    //puts("asdf");
    while(row < rows && col >= 0){
        if(a[row * cols + col] == num)
            return true;
        if(a[row * cols + col] > num)
            col --;
        else row ++;
    }
    return false;
}
void test(){
    int a[][4] =  {{1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}};
    bool ans = find((int*)a, 4, 4, 15);
    if( ans )
        puts("yes");
    else
        puts("no");
}
int main(){
    test();
    return 0;
}
View Code

 

 20.

旋转数组二分查找

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;




int a[111];
void solve(int st, int ed, int num){
    int index1 = st, index2 = ed, mid = st;
    while(index1 <= index2){
        int mid = index1 + index2 >> 1;
        if(a[mid] == num){
            puts("yes");
            return;
        }
        if(a[mid] >= a[st]){
            if(num < a[mid] && num >= a[index1])
                index2 = mid - 1;
            else
                index1 = mid + 1;
        }else{
            if(num > a[mid] && num <= a[index2])
                index1 = mid + 1;
            else
                index2 = mid - 1;
        }
    }
    puts("no");
}
int main(){
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i ++)
        scanf("%d", a + i);
    int num;
    scanf("%d", &num);
    solve(0, n - 1, num);
    return 0;
}
View Code

 

 21.

给一个数,打印从1到这个数位数的最大数字

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;




void PrintNum(char *num){
    int len = strlen(num);
    bool f = 1;
    for(int i = 0; i < len; i ++){
        if(f && num[i] == '0')
            continue;
        else f = 0;
        putchar(num[i]);
    }
    printf("\t");
}
bool Increment(char *num){
    bool isOverflow = false;
    int nTakeover = 0;
    int len = strlen(num);
    for(int i = len - 1; i >= 0; i --){
        int sum = num[i] - '0' + nTakeover;
        if(i == len - 1)
            sum ++;
        if(sum >= 10){
            if(i == 0)
                isOverflow = true;
            else{
                sum -= 10;
                nTakeover = 1;
                num[i] = '0' + sum;
            }
        }else{
            num[i] = '0' + sum;
            break;
        }
    }
    return isOverflow;
}
int main(){
    int n;
    scanf("%d", &n);
    char *num = new char [n + 1];
    memset(num, '0', n);
    num[n] = '\0';
    while(!Increment(num)){
        PrintNum(num);
    }
    delete [] num;
    return 0;
}
code2
#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;




void PrintNum(char *num){
    int len = strlen(num);
    bool f = 1;
    for(int i = 0; i < len; i ++){
        if(f && num[i] == '0')
            continue;
        else f = 0;
        putchar(num[i]);
    }
    printf("\t");
}
void f(char *num, int len, int index){
    if(index == len - 1){
        PrintNum(num);
        return;
    }
    for(int i = 0; i < 10; i ++){
        num[index + 1] = i + 48;
        f(num, len, index+1);
    }
}
int main(){
    int n;
    scanf("%d", &n);
    char *num = new char [n + 1];
    memset(num, '0', n);
    num[n] = '\0';
    for(int i = 0; i < 10; i ++){
        num[0] = i + 48;
        f(num, n, 0);
    }
    delete [] num;
    return 0;
}
code2

 

 22.

判断一棵树是不是平衡二叉树

解决方案:要想知道是不是平衡二叉树,就得先知道该点左右孩子深度之差,超过二就不是 了

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;


struct TreeNode{
    int value;
    TreeNode *left;
    TreeNode *right;
};
TreeNode *creatTreeNode(int m){
    TreeNode *node = new TreeNode;
    node->value = m;
    node->right = node->left = NULL;
    return node;
}
void DestroyTree(TreeNode *root){
    if(root != NULL){
        TreeNode *l = root->left;
        TreeNode *r = root->right;
        delete root;
        root = NULL;
        DestroyTree(l);
        DestroyTree(r);
    }
}
void connectTree(TreeNode *root, TreeNode *l, TreeNode *r){
    if(root != NULL){
        root->left = l;
        root->right = r;
    }
}
bool fun(TreeNode *root, int &depth){
    if(root == NULL){
        depth = 0;
        return true;
    }
    int l_depth, r_depth;
    if(fun(root->left, l_depth) && fun(root->right, r_depth)){
        int diff = l_depth - r_depth;
        if(diff <= 1 && diff >= -1){
            depth = 1 + (l_depth > r_depth ? l_depth : r_depth);
            return true;
        }
    }
    return false;
}

int main(){
    TreeNode *node1 = creatTreeNode(1);
    TreeNode *node2 = creatTreeNode(2);
    TreeNode *node3 = creatTreeNode(3);
    TreeNode *node4 = creatTreeNode(4);
    TreeNode *node5 = creatTreeNode(5);
    TreeNode *node6 = creatTreeNode(6);
    TreeNode *node7 = creatTreeNode(7);

    connectTree(node1, node2, node3);
    connectTree(node2, node4, node5);
    connectTree(node3, node7, node6);
    //connectTree(node5, node7, NULL);

    int depth = 0;
    if(fun(node1, depth))
        puts("yes");
    else
        puts("no");
    printf("%d\n", depth);

    DestroyTree(node1);
    return 0;
}
View Code

 

 23.

统计一个排序数组中某一数字出现的次数

解决方案:两次二分查找,第一次查询该数字最左边位置,第二次最右边,因为连续,所以差值+1就是该数字个数了

    二分查找时,要稍微处理下

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;


int a[8] = {1,3,3,3,3,3,3,7};
int len = 8;
int getFirstK(int l, int r, int k){
    //int l = 0, r = len - 1;
    if(l > r) return -1;
    int mid = l + r >> 1;
    if(a[mid] == k){
        if((mid && a[mid - 1] != k) || mid == 0)
            return mid;
        else
            r = mid - 1;
    }else
        if(a[mid] < k)
            l = mid + 1;
        else
            r = mid - 1;
    return getFirstK(l, r, k);
}
int getLastK(int l, int r, int k){
    //int l = 0, r = len - 1;
    if(l > r) return -1;
    int mid = l + r >> 1;
    if(a[mid] == k){
        if((mid != len - 1 && a[mid + 1] != k) || mid == len - 1)
            return mid;
        else
            l = mid + 1;
    }else
        if(a[mid] < k)
            l = mid + 1;
        else
            r = mid - 1;
    return getLastK(l, r, k);
}

int main(){
    int first = getFirstK(0, len-1, 2);
    int last = getLastK(0, len-1, 2);
    if(first > -1 && last > -1)
        printf("%d\n", last - first + 1);
    else
        puts("no");
    return 0;
}
View Code

 

24.

一个整型数组里除了两个数字之外,其他的数字都出现了两次,求这两个数字。时间O(n),空间O(1)

解决方案:异或所有元素,求最右边的1,然后按这情况将数组分为两组

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;

int a[8] = {2,4,3,6,3,2,5,5};
int len = 8;
bool is_ok(int num, int cnt){
    num = num >> cnt;
    return (num & 1);
}
int main(){
    int res = 0;
    for(int i = 0; i < len; i ++)
        res ^= a[i];
    int cnt = 0;
    while((res & 1) == 0 && cnt < 32){
        res = res >> 1;
        cnt ++;
    }    
    int ans1 = 0, ans2 = 0;
    for(int i = 0; i < len; i ++){
        if(is_ok(a[i], cnt))
            ans1 ^= a[i];
        else
            ans2 ^= a[i];
    }
    printf("%d %d\n", ans1, ans2);
    return 0;
}
View Code

 

 25.

输入一个正整数,打印出所有和为该数的正数序列

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;



void printf_n(int l, int r){
    for(int i = l; i < r; i ++){
        printf("%d ", i);
    }
    printf("%d\n", r);
}
void solve(int n){
    int l = 1, r = 2;
    if(n < 3) return;
    int mid = 1 + n >> 1;
    int sum = l + r;
    while( l < mid){
        if(sum == n)
            printf_n(l, r);
        while(l < mid && sum > n){
            sum -= l;
            l ++;
            if(sum == n)
                printf_n(l, r);
        }
        r ++;
        sum += r;
    }
}
int main(){
    int n;
    scanf("%d", &n);
    solve(n);
    return 0;
}
View Code

 

 26.

二叉搜索树不创建新的结点转换成双向链表

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;



struct TreeNode{
    int value;
    TreeNode *left;
    TreeNode *right;
};
TreeNode *creatTreeNode(int m){
    TreeNode *node = new TreeNode;
    node->value = m;
    node->right = node->left = NULL;
    return node;
}
void DestroyTree(TreeNode *root){
    if(root != NULL){
        TreeNode *l = root->left;
        TreeNode *r = root->right;
        delete root;
        root = NULL;
        DestroyTree(l);
        DestroyTree(r);
    }
}
void connectTree(TreeNode *root, TreeNode *l, TreeNode *r){
    if(root != NULL){
        root->left = l;
        root->right = r;
    }
}


void covertToDoubleList(TreeNode **head, TreeNode **list, TreeNode  *root){
    //TreeNode *root = tt;
    root->left = *list;
    if(NULL != *list)
        (*list)->right = root;
    else
        (*head) = root;
    (*list) = root;
    printf("%d ", root->value);
}
void fun(TreeNode **head, TreeNode **list, TreeNode *root){
    if(NULL == root)
        return;
    if(NULL != root->left)
        fun(head, list, root->left);
    covertToDoubleList(head, list, root);
/*
    root->left = *list;
    if(NULL != *list)
        (*list)->right = root;
    else
        (*head) = root;
    (*list) = root;
    printf("%d ", root->value);
*/
    if(NULL != root->right)
        fun(head, list, root->right);
}
void solve(TreeNode *root){
    TreeNode *head = new TreeNode();
    TreeNode *list = new TreeNode();
    head = list = NULL;
    //if(head == NULL)puts("adsf");
    fun(&head, &list, root);
    puts("");
    TreeNode *p = head;
    while(p != NULL){
        printf("%d ", p->value);
        p = p->right;
    }
    puts("");
}
int main(){
    TreeNode *node1 = creatTreeNode(10);
    TreeNode *node2 = creatTreeNode(6);
    TreeNode *node3 = creatTreeNode(14);
    TreeNode *node4 = creatTreeNode(4);
    TreeNode *node5 = creatTreeNode(8);
    TreeNode *node6 = creatTreeNode(12);
    TreeNode *node7 = creatTreeNode(16);
    connectTree(node1, node2, node3);
    connectTree(node2, node4, node5);
    connectTree(node3, node6, node7);
    solve(node1);
    //DestroyTree(node1);
    return 0;
}
View Code

 

 27.

找出数组中次数超过一半的数字

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;



int a[9] = {1,2,2,3,2,2,5,4,2};
int len = 9;
bool check(int num){
    int cnt = 0;
    for(int i = 0; i < len; i ++)
        if(a[i] == num)
            cnt ++;
    if(cnt * 2 <= len)
        return false;
    else
        return true;
}
void solve(){
    int res = a[0];
    int cnt = 1;
    for(int i = 1; i < len; i ++){
        if(cnt == 0){
            res = a[i];
            cnt ++;
        }else
            if(a[i] == res)
                cnt ++;
            else cnt --;
    }
    if(check(res))
        puts("yes");
    else
        puts("no");
}
int main(){
    solve();
    return 0;
}
View Code

 

 28.

给定一个整数,求从1到这整数十进制中1出现的次数

解决方案:

分析(转)

简单的方法就是按照给位进行分析

在个位出现1的个数=n/10+(个位=0,0;个位>1,1;个位=1,低0位+1);

十位位出现1的个数=n/100*10+(十位=0,0;十位>1,10,;十位=1,低一位+1);

百位出现1的个数=n/1000*100+(百位=0,0;百位>1,100;百位=1,低两位+1);

等等

算法的复杂度仅仅和位数有关

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;



int f(int a){
    if(a == 0) return 1;
    int num = 1;
    for(int i = 1; i <= a; i ++)
        num *= 10;
    return num;
}
int solve(int n){
    int tmp = n;
    int len = 0;
    while(tmp){
        tmp /= 10;
        len ++;
    }
    tmp = n;
    int sum = 0;
    for(int i = 1; i <= len; i ++){
        sum += tmp / f(i) * f(i-1);
        int t = n / f(i-1) % 10;
        if(t == 1)
            sum += n % f(i-1) + 1;
        else if(t > 1)
            sum += f(i-1);
    }
    return sum;
}
int main(){
    int n;
    scanf("%d", &n);
    int t = solve(n);
    printf("%d\n", t);
    return 0;
}
View Code

 

 29.

把数组排成最小的数

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <string>
#include <queue>
using namespace std;



int a[3] = {3,32,321};
const int len = 3;


int cmp(const string &s1, const string &s2){
    string ss1 = s1 + s2;
    string ss2 = s2 + s1;
    return s1 > s2;
}
int main(){
    char s[len+1][10];
    string ss[len];
    for(int i = 0; i < len; i ++){
        sprintf(s[i], "%d", a[i]);
        ss[i] = s[i];
    }
    sort(ss,ss + len, cmp);
    for(int i = 0; i < len; i ++)
        //printf("%s", s[i]);
        cout<<ss[i];
    puts("");
    return 0;
}
View Code

 

 30.

寻找丑数(只包含因子为2 3 5的数)

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <string>
#include <queue>
using namespace std;



int Min(int a, int b, int c){
    int x = a < b ? a: b;
    x = x < c ? x : c;
    return x;
}
int getUgly(int n){
    if(n <= 0) return 0;
    int *ugly = new int[n];
    ugly[0] = 1;
    int cnt = 1;
    int *m2 = ugly;
    int *m3 = ugly;
    int *m5 = ugly;
    while(cnt < n){
        int min = Min(*m2 * 2, *m3 * 3, *m5 * 5);
        ugly[cnt] = min;
        while(*m2 * 2 <= ugly[cnt])
            m2 ++;
        while(*m3 * 3 <= ugly[cnt])
            m3 ++;
        while(*m5 * 5 <= ugly[cnt])
            m5 ++;
        cnt ++;
    }
    int ans = ugly[n - 1];
    delete [] ugly;
    return ans;
}
int main(){
    int n;
    scanf("%d", &n);
    int t =    getUgly(n);
    printf("%d\n", t);
    return 0;
}
View Code

 

 31.

在字符串中找出第一个只出现一次的字符

解决方案:

先遍历一次建立hash表,然后查找就行

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <string>
#include <queue>
using namespace std;



int main(){
    char s[333];
    scanf("%s", s);
    int hashmap[270];
    memset(hashmap, 0, sizeof hashmap);
    for(int i = 0; s[i]; i ++)
        hashmap[s[i]] ++;
    bool f = true;
    for(int i = 0; s[i]; i ++){
        if(hashmap[s[i]] == 1){
            printf("%c\n", s[i]);
            f = false;
            break;
        }
    }
    if(f)
        puts("not found");
    return 0;
}
View Code

 

 32.

判断一个序列是不是某二叉排序树(二叉搜索树,二元查找树)的后序遍历序列

解决方案:

最后一个结点必为根结点,然后根据二叉排序树的性质找到它的左右孩子,然后再递归查找

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <string>
#include <queue>
using namespace std;



bool check(int *a, int n){
    if(a == NULL || n < 1)
        return false;
    int root = a[n-1];
    int l = 0;
    for(; l < n - 1; l ++){
        if(a[l] > root)
            break;
    }
    int r = l;
    for(; r < n - 1; r ++)
        if(a[r] < root)
            return false;
    bool left = true;
    if(l > 0)
        left = check(a, l);
    bool right = true;
    if(r < n - 1)
        right = check(a+l, n - l + 1);
    return (left && right);
}
int main(){
    int n;
    scanf("%d", &n);
    int *a = new int[n];
    for(int i = 0; i < n; i ++){
        scanf("%d", a + i);
    }
    bool ans = check(a, n);
    if(ans)
        puts("yes");
    else
        puts("no");
    return 0;
}
View Code

 

33.

约瑟夫环问题

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <string>
#include <queue>
using namespace std;



int main(){
    int n;
    scanf("%d", &n);    
    int m;
    scanf("%d", &m);
    int last = 0;
    for(int i = 2; i <= n; i ++)
        last = (last + m) % i;
    printf("%d\n", last);
    return 0;
}
View Code

 

 34.

输入两个整数n和m,从数列1,2.......n中随意取几个数,使其和等于m,要求将其中所有的可能组合列出来

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <string>
#include <queue>
using namespace std;


void solve(int n, int m){
    if(n < 1 || m < 1)
        return;
    if(n > m)
        n = m;
    int maxn = 1 << n;
    for(int i = 1; i < maxn; i ++){
        int sum = 0;
        for(int j = i, k = 1; j; j >>= 1, k ++)
            if(j&1)
                sum += k;
        if(sum == m){
            for(int j = i, k = 1; j; j >>= 1, k ++)
                if(j&1)
                    printf("%d ", k);
            puts("");
        }
    }
}
int main(){
    int n, m;
    scanf("%d%d", &n, &m);
    solve(n, m);
    return 0;
}
View Code

 

 35.

将一个整数以字符串输出

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <string>
#include <queue>
using namespace std;




char *int2str(int n){
    char *s = new char;
    char *p = s;
    bool f = true;
    if(n == 0){
        *p ++ = '0';
        *p ++ = '\0';
        return s;
    }else
        if(n < 0){
            f = false;
            n = - n;
        }
    int len = 0;
    while(n){
        *p ++ = n % 10 + 48;
        n /= 10;
        ++ len;
    }
    if(!f){
        len ++;
        *p ++ = '-';
    }
    *p ++ = '\0';
    //printf("%d %s\n\n", len, s);
    for(int i = 0; i < len / 2; i ++){
        char c = s[i];
        s[i] = s[len - i - 1];
        s[len - i - 1] = c;
    }
    return s;
}
int main(){
    int n;
    scanf("%d", &n);
    char *s = int2str(n);
    printf("%s\n", s);
    return 0;
}
View Code

 

 36.

求两个字符串的最长连续公共子串并返回分别在两个子串中的位置

#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include <string>
#include <queue>
using namespace std;



char *lcs(int &index1, int &index2, char *s1, char *s2){
    int mat[111][111];
    memset(mat, 0, sizeof mat);
    int maxlen = 0;
    for(int i = 0; s1[i]; i ++){
        for(int j = 0; s2[j]; j ++){
            if(s1[i] == s2[j]){
                if(i && j){
                    mat[i][j] = mat[i-1][j-1] + 1;
                }
                else mat[i][j] = 1;
                if(mat[i][j] > maxlen){
                    maxlen = mat[i][j];
                    index1 = i;
                    index2 = j;
                }
            }
        }
    }
    char *s = new char[maxlen+1];
    for(int i = 0; i < maxlen; i ++){
        s[i] = s1[index1 - maxlen + i + 1];
    }
    index1 = index1 - maxlen + 1;
    index2 = index2 - maxlen + 1;
    s[maxlen] = '\0';
    return s;
}
int main(){
    char s1[111], s2[111];
    while(~scanf("%s%s", s1, s2)){
        int index1, index2;
        char *s = lcs(index1, index2, s1, s2);
        printf("%s %d %d\n", s, index1, index2);
    }
    return 0;
}
View Code

 

 

 

 

 

posted on 2013-09-21 07:16  louzhang_swk  阅读(2340)  评论(2编辑  收藏  举报