剑指offer

6. 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。

http://ac.jobdu.com/problem.php?pid=1385

记录:postIdx每个case前记得要初始化;post数组填充的位置应该在子树填充完之后;如何in中找不到root证明无法构建返回错误。

#include<cstdio>

int pre[1005];
int in[1005];
int post[1005];
int postIdx=0;

int build(int pre[], int in[],int n){
    if(n<=0)
        return 1;
    int rootVal = pre[0];
    int rootIdx = -1;
    for(int i=0;i<n;i++){
        if(in[i]==rootVal){
            rootIdx = i;
            break;
        }
    }
    if(rootIdx==-1)
        return 0;
    
    int left = build(pre+1,in,rootIdx);
    int right = build(pre+1+rootIdx,in+1+rootIdx,n-1-rootIdx);

    post[postIdx++]=rootVal;

    return left&&right;
}


int main(){
//    freopen("data.in","r",stdin);
//    freopen("data.out","w",stdout);
    int n;
    while(scanf("%d",&n)!=EOF){
        postIdx=0;
        for(int i=0;i<n;i++)
            scanf("%d",&pre[i]);
        for(int i=0;i<n;i++)
            scanf("%d",&in[i]);

        int res = build(pre,in,n);
        if(res){
            for(int i=0;i<n;i++){
                printf("%d ",post[i]);
            }
            printf("\n");
        }else{
            printf("No\n");
        }

    }

    return 0;
}

 

8. 旋转数组的最小数字

http://ac.jobdu.com/problem.php?pid=1386

记录:此题是二分查找的变体,需要考虑各种边界情况,注意重复元素。 可以以1,2,3,4,5和1,1,2,2等例子旋转后进行分析。

 

#include<stdio.h>
int a[1000005];
 
int getMin(int l, int r) {
    int min = 0x7fffffff;
    int i;
    for (i = l; i <= r; i++)
        if (a[i] < min) {
            min = a[i];
        }
 
    return min;
}
 
int main() {
//  freopen("in.txt", "r", stdin);
    int n;
    while (scanf("%d", &n) != EOF) {
        int i;
        for (i = 0; i < n; i++)
            scanf("%d", &a[i]);
 
        if (a[0] < a[n - 1]) { //no pivot
            printf("%d\n", a[0]);
 
        } else {
            int l = 0;
            int r = n - 1;
            int mid;
            int breakOut = 0;
            while (r - l > 1) {
                mid = (l + r) / 2;
                if (a[mid] == a[l] && a[mid] == a[r]) {
                    printf("%d\n", getMin(l, r));
                    breakOut = 1;
                    break;
                }
 
                if (a[mid] > a[l]) {
                    l = mid;
                } else {
                    r = mid;
                }
 
            }
            if (!breakOut)
                printf("%d\n", a[r]);
 
        }
 
    }
 
    return 0;
}

 

10. 二进制中1的个数。

扩展:

1. 如何判断一个数是2的幂。

2. 计算需要改变多少位能把m变成n。

int numberOfOne(int n){
    int count =0;

    while(n){
        count++;
        n = n&(n-1);
    }
    return count;
}

 

11. 数值的整数次方

  注意各种异常情况的处理。

  学习设置flag这种标记错误的方式。

  注意求幂的时候二分的运用。

  注意double的比较 return a-b>-0.0000001&&a-b<0.0000001;

#include<stdio.h>
 
#define NO_MEANING 1
 
int equal(double a, double b) {
    if (a - b > -0.0000001 && a - b < 0.0000001)
        return 1;
    else
        return 0;
}
 
double recursivePow(double base, unsigned int exp) {
    if (exp == 0)
        return 1.0;
    else if (exp == 1)
        return base;
 
    if (exp % 2 == 0) {
        double half = recursivePow(base, exp / 2);
        return half * half;
    } else {
        double half = recursivePow(base, (exp - 1) / 2);
        return half * half * base;
    }
 
}
 
double myPow(double base, int exp, int* flag) {
 
    if (equal(base, 0.0)) {
        if (exp <= 0) {
            *flag = NO_MEANING;
            return 0.0;
        } else
            return 0.0;
    }
 
    if (exp == 0)
        return 1.0;
    else if (exp == 1)
        return base;
 
    double res = 1;
    int neg = 0;
 
    if (exp < 0) {
        exp = -exp;
        neg = 1;
    }
    res = recursivePow(base, (unsigned int) exp);
 
    if (neg)
        res = 1 / res;
 
    return res;
 
}
 
int main() {
//  freopen("in.txt", "r", stdin);
    int n;
    scanf("%d", &n);
    double base;
    int exp;
    while (n--) {
        scanf("%lf%d", &base, &exp);
        int flag = 0;
        double res = myPow(base, exp, &flag);
        if (!flag)
            printf("%.2ef\n", res);
        else
            printf("INF\n");
 
    }
 
    return 0;
}
 
/**************************************************************
    Problem: 1514
    User: jdflyfly
    Language: C++
    Result: Accepted
    Time:80 ms
    Memory:1020 kb
****************************************************************/

 

12. 打印1到最大的n位数:考察大数问题。

1. 字符串处理。

2. 递归生成permutation,注意leading 0的处理。

#include<stdio.h>

int a[1000];

void print(int n,int cur){
    if(cur==n){
        //print the res, be careful with the leading 0
        int meetNonZero =0;
        for(int i=0;i<n;i++){
            if(meetNonZero){
                printf("%d",a[i]);
                continue;
            }
            if(a[i]!=0){
                meetNonZero=1;
                printf("%d",a[i]);
            }

        }
        if(meetNonZero)
            printf("\n");
        return;
    }
    for(int i=0;i<10;i++){
        a[cur]=i;
        print(n,cur+1);
    }

}

int main(){
    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);
    int n;
    while(scanf("%d",&n)!=EOF){
        print(n,0);        
    }
    return 0;
}

 

14 调整数组顺序使奇数位于偶数前面

 

16. 反转链表

注意null等各种边界情况。

记录:学会用pre,cur,post等临时变量

#include<stdio.h>

struct Node {
    int val;
    Node*next;
    Node(int v) :
            val(v), next(NULL) {
    }

};

Node* reverse(Node* head) {
    Node* newHead = NULL;
    Node* pre = NULL;
    Node* cur = head;
    Node* post = NULL;

    while (cur != NULL) {
        post = cur->next;
        if (post == NULL)
            newHead = cur;
        cur->next = pre;

        pre = cur;
        cur = post;

    }
    return newHead;

}

void printList(Node* head) {
    if (head == NULL) {
        printf("NULL\n");
        return;
    }

    Node* p = head;
    while (p != NULL) {
        if (p != head)
            printf(" ");
        printf("%d", p->val);
        p = p->next;
    }
    printf("\n");
}

int main() {
//    freopen("my.in", "r", stdin);
//    freopen("my.out", "w", stdout);

    int n;
    while (scanf("%d", &n) != EOF) {
        Node* dummyHead = new Node(-1);
        Node* p = dummyHead;
        int tmp;
        for (int i = 0; i < n; i++) {

            scanf("%d", &tmp);
            p->next = new Node(tmp);
            p = p->next;
        }

        Node* revHead = reverse(dummyHead->next);
        printList(revHead);

    }

    return 0;
}

 

 

22 栈的压入、弹出序列

  

#include<stdio.h>
#include<stdlib.h>
#include<stack>

using namespace std;

int in[100005];
int out[100005];

int main() {
//    freopen("my.in", "r", stdin);
//    freopen("my.out", "w", stdout);

    int n;
    while (scanf("%d", &n) != EOF) {
        for (int i = 0; i < n; i++)
            scanf("%d", &in[i]);

        for (int i = 0; i < n; i++)
            scanf("%d", &out[i]);

        int i = 0, j = 0;
        stack<int> stack;
        int ok = 1;
        while (j < n) {
            if (!stack.empty() && stack.top() == out[j]) {
                stack.pop();
                j++;
            } else {
                if (i < n) {
                    stack.push(in[i++]);
                } else {
                    ok = 0;
                    break;
                }

            }

        }
        if (ok)
            printf("Yes\n");
        else
            printf("No\n");

    }

    return 0;
}

 

 

34 丑数生成。

记录:分别维护3个指针,每次选取其中最小的,选完之后更新其他指针,小于当前值

#include<stdio.h>

int uglyNum[1505];

int getMin(int a, int b, int c) {
    int min = a;
    if (b < min)
        min = b;
    if (c < min)
        min = c;
    return min;
}

int main() {
//    freopen("my.in", "r", stdin);
//    freopen("my.out", "w", stdout);

    int n;
    while (scanf("%d", &n) != EOF) {
        uglyNum[0] = 1;
        int p = 1;
        int p2 = 0;
        int p3 = 0;
        int p5 = 0;
        int min;
        while (p < n) {
            min = getMin(uglyNum[p2] * 2, uglyNum[p3] * 3, uglyNum[p5] * 5);
            uglyNum[p] = min;
            while (uglyNum[p2] * 2 <= min)
                p2++;
            while (uglyNum[p3] * 3 <= min)
                p3++;
            while (uglyNum[p5] * 5 <= min)
                p5++;

            p++;
        }
        printf("%d\n", uglyNum[n - 1]);

    }

    return 0;
}

 

36 数组中的逆序对

利用mergesort,复杂度nlogn。

  注意每次统计merge的时候如何统计count。

  注意count比较大,超出了int范围,应该用long long

#include<stdio.h>
#include<stdlib.h>

int a[100005];
long long count;

void merge(int a[], int b[], int left, int mid, int right) {
    int p1 = left;
    int p2 = mid + 1;
    int p = left;
    while (p1 <= mid && p2 <= right) {
        if (a[p1] <= a[p2]) {
            b[p++] = a[p1++];
        } else {
            b[p++] = a[p2++];
            //p1~mid范围都比p2大,所以count要增加mid-p1+1;
            count += mid - p1 + 1;

        }
    }
    while (p1 <= mid)
        b[p++] = a[p1++];
    while (p2 <= right)
        b[p++] = a[p2++];

    for (int i = left; i <= right; i++)
        a[i] = b[i];

}

void mergeSort(int a[], int b[], int left, int right) {
    if (left < right) {
        int mid = left + (right - left) / 2;
        mergeSort(a, b, left, mid);
        mergeSort(a, b, mid + 1, right);
        merge(a, b, left, mid, right);
    }

}

int main() {
//    freopen("my.in", "r", stdin);
//    freopen("my.out", "w", stdout);

    int n;
    while (scanf("%d", &n) != EOF) {
        for (int i = 0; i < n; i++)
            scanf("%d", &a[i]);
        count = 0;
        int* b = (int*) malloc(sizeof(int) * n);
        mergeSort(a, b, 0, n - 1);
        //不要忘记了free掉
        free(b);
        printf("%lld\n", count);
    }

    return 0;
}

 

43 n个骰子的点数

n个骰子,每个数值1~m,求所有情况的概率。

 

思路1:递归生成,一次枚举每个扇子的m中情况。

思路2:递推法,对于新加的一个骰子,此时和为n的骰子出现的次数应该等于上一次循环中点数和为n-1,n-2,n-3,n-4,n-5,n-6的次数的和。

 

思路1代码:

int maxValue;

void calcuHelper(int number, int count, int sum, int*pro) {
    if (count == number) {
        pro[sum - number]++;
        return;
    }

    for (int i = 1; i <= maxValue; i++) {
        calcuHelper(number, count + 1, sum + i, pro);
    }

}

void calcu(int number, int* pro) {
    calcuHelper(number, 0, 0, pro);
}

void printProbability(int number) {
    if (number < 1)
        return;
    int maxSum = maxValue * number;

    int* pProbability = new int[maxSum - number + 1];
    for (int i = number; i <= maxSum; i++)
        pProbability[i - number] = 0;

    calcu(number, pProbability);

    int total = pow(maxValue, number);
    for (int i = number; i <= maxSum; i++) {
        double ratio = (double) pProbability[i - number] / total;
        printf("%d:%.2lf\n", i, ratio);
    }
    delete[] pProbability;

}

 

44 扑克牌的顺子

记录:先排序,然后统计0的个数和间隔的个数,看0是否能填满。

#include<stdio.h>
#include<math.h>
#include<algorithm>

using namespace std;

bool isContinuous(int* numbers, int n) {
    if (numbers == NULL || n <= 0)
        return false;

    sort(numbers, numbers + n);
    int numOfZero = 0;
    int numOfGap = 0;

    int idx = 0;
    for (; idx < n; idx++) {
        if (numbers[idx] == 0) {
            numOfZero++;
        } else
            break;
    }

    int pre = idx;
    int cur = pre + 1;
    while (cur < n) {
        if (numbers[pre] == numbers[cur])
            return false;
        numOfGap += numbers[cur] - numbers[pre] - 1;
        pre = cur;
        cur++;
    }

    return (numOfGap > numOfZero) ? false : true;

}

int a[20];

int main() {
    //freopen("my.in", "r", stdin);
    //freopen("my.out", "w", stdout);

    int n;
    while (scanf("%d", &n) != EOF) {
        if (n == 0)
            break;
        for (int i = 0; i < n; i++)
            scanf("%d", &a[i]);
        if (isContinuous(a, n))
            printf("So Lucky!\n");
        else
            printf("Oh My God!\n");

    }

    return 0;
}

 

45 约瑟夫环问题,n个数字组成的环,从数字0开始每次删除第m个,求最后删除的数字。

记录:递推公式 f(n,m)=[f(n-1,m)+m]%n,初始值:f(1,m)=0;

#include<stdio.h>
#include<math.h>
#include<algorithm>

using namespace std;

int lastRemaining(int n, int m) {
    if (n < 1 || m < 1)
        return -1;
    int last = 0;
    for (int i = 2; i <= n; i++)
        last = (last + m) % i;

    return last + 1;
}

int main() {
    //freopen("my.in", "r", stdin);
    //freopen("my.out", "w", stdout);

    int n, m;
    while (scanf("%d", &n) != EOF) {
        if (n == 0)
            break;
        scanf("%d", &m);

        printf("%d\n", lastRemaining(n, m));

    }

    return 0;
}

 

posted @ 2014-09-02 15:49  jdflyfly  阅读(245)  评论(0编辑  收藏  举报