剑指offer--编程题参考代码(2)

继续分享剑指offer的代码,大家可以去牛客网上刷一刷,我分享的都是通过的。大家可以自己写,优化一下哦。这篇主要放几个操作链表的题,加强对链表的熟悉,后面是数组的题。

9.输入一个链表,输出该链表中倒数第k个结点。

<span style="font-size:14px;">/*
struct ListNode {
 int val;
 struct ListNode *next;
 ListNode(int x) :
   val(x), next(NULL) {
 }
};*/
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(pListHead==NULL||k==0)
            return NULL;
       ListNode* p_temp = pListHead;  //一条用于从头遍历到k-1的位置
       ListNode* q = pListHead;
       int i=0;
       while( i<k-1) {
           p_temp = p_temp->next;
           i++ ;
           if(p_temp == NULL)
               return NULL;
       }
        while(p_temp->next!=NULL){
            p_temp = p_temp->next;
            q= q->next;
        }
        return q;
    }
};</span>

10.约瑟夫问题(m>n可以)
已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。
通常解决这类问题时我们把编号从0~n-1,最后[1]  结果+1即为原问题的解。

这里我用一个循环链表。大家可以看有构建链表,插入结点。以及遍历之后删除结点的操作(基本的链表增删改)

class Solution {
public:
    int LastRemaining_Solution(unsigned int n, unsigned int m)
    {
        if(m==0||n==0)
            return -1;
        struct Lnode{
            int data;
            Lnode* next;
        };
        int len = sizeof(struct Lnode);
        unsigned int i=1;
        struct Lnode* head = (struct Lnode*)malloc(len);
        head->data=0;          //因为需要一个圈,这里是头结点(也就是带数据的),不是头指针。
        head->next=NULL;
        struct Lnode* cur = head;
        while(i<n){
        struct Lnode* p = (struct Lnode*)malloc(len);
        p->data=i;
        p->next=NULL;
        cur->next = p;
        cur = p ;
        i++;
        }
        cur->next = head;  //形成循环链表,首尾相连了
         
          Lnode* q=head;
          Lnode* pre;        //为下面删除结点定义一个前驱
    while(n>1){              //删除数到的结点
         i=0;
        while(i++<m-1){      //遍历到第m-1个结点
           pre=q;
           q=q->next;
        }
         pre->next=q->next;
         free(q);
          q=pre->next; 
        --n;
       }
      return (q->data);  
    }
};


11.用两个栈实现一个队列。
一般的,标准库里栈,队的操作函数:
队列:#include<queue>
申请队列:queue<type>q;
判队空:q.empty();
获取队头元素:q.front();
入队:q.push();
出队:q.pop();
栈:#include<stack>
申请栈:stack<type>s;
入栈:s.push();
出栈:s.pop();
获取栈顶元素:s.top();
判栈空:s.empty();


class Solution
{
public:
    void push(int node) {           //入队:元素都压入栈1,直到栈2空,在node入栈(入队)
        while(!stack2.empty())
            {
              stack1.push(stack2.top());
              stack2.pop();
        }
         stack1.push(node);
    }

    int pop() {
        while(!stack1.empty())  //出队:元素都压入栈2,直到栈1空,栈顶元素出栈,即出队
            {        
             stack2.push(stack1.top());
             stack1.pop();
        }
        int m=stack2.top();
        stack2.pop();
      return   m;
    }


private:
    stack<int> stack1;
    stack<int> stack2;
};

12.设有一个带表头结点的双向循环链表L,每个结点有4个数据成员:指向先驱结点的指针prior、指向后继结点的指针next、存放数据的成员data和访问频度freq。所有结点的freq初始时都为0.每当在链表上进行一次L.Locate(x)操纵时,令元素值x的结点的访问频度freq加1,并将该结点前移,链接到现它的访问频度相等的结点后面,使得链表中所有结点保持按访问频度递减的顺序排列,以使频繁访问的结点总是靠近表头。
 void Locate(int &x)
 {
 < 结点类型说明 >
 *p = first->next;
 while (p != first &&  p->data!=x ) p = p->next;
 if (p != first)
 {
   p->freq++ ;
 < 结点类型说明 >
 *current = p;
 current->prior->next = current->next;
 current->next->prior = current->prior;
 p = current->prior;
 while (p != first && p->freq < current->freq  ) p = p->prior;
 current->next = p->next  ;
 current->prior = p;
 p->next->prior = current;
 p->next = current;
 }
 else
 printf(“Sorry. Not find!\n”);  \*没找到*\
 }
//这里是对双向循环链表的遍历和移动结点

13.二维数组中的查找。
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。
请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

class Solution {
public:
    bool Find(vector<vector<int> > array,int target) {
        int raw=array.size();
        int col=array[0].size();   //左下角开始,右增,上减
        int m=raw-1,n=0;
        while(m>=0&&n<col){
            if(target==array[m][n])
                return true;
            else if(target>array[m][n])
                ++n;
            else 
                --m;
        }
         return false;   
    }
};

14.调整数组顺序使奇数位于偶数前面
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,
所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变
class Solution {
public:
    void reOrderArray(vector<int> &array) {
        int m=array.size();
        int i=0,j=m-1,k=0;
       int a[m];
          for(int i=0;i<m;i++)  //奇数存头,偶数存尾。
            a[i]=0;
       // int* a=new int[m]();
        while(i<m){
            if(array[i]%2==0)
                a[j--]=array[i];
            if(array[i]%2==1)
                a[k++]=array[i];
            ++i;
        }
         j++;
        for(i=0;i<j;i++)      //新数组从头取完奇数
            array[i]=a[i];
        for(k=m-1;k>=j;k--)    //新数组从尾倒取完偶数
            array[i++]=a[k];
    }
};




Offer》 1. 赋运算函数 2. 单例设计模式 3. 二维数组中查找目标 4. 替换字符串中的空格 5. 从尾到头打印链表 6. 由前序和中序遍历重建二叉树 7. 用两个实现队列 8. 求旋转数组的最小数字 9. 斐波那契数列的第n项(青蛙跳台阶) 10. 二进制中1的个数 11. 数的整数次方 12. 打印1到最大的n位数 13. O(1)间删除链表节点 14. 使数组中的奇数位于偶数前面 15. 找链表中倒数第K个节点 16. 输出反转后的链表 17. 合并两个有序链表 18. 判断二叉树A中是否包含子树B 19. 二叉树的镜像 20. 顺针打印矩阵 21. 包含min函数 22. 判断一个是否是另一个的弹出序列 23. 层序遍历二叉树 24. 后序遍历二叉搜索树 25. 二叉树中和为某的路径 26. 复杂链表的复制 27. 二叉搜索树转换为双向链表 28. 打印字符串中所有字符的排列 29. 数组中出现次数超过一半的数字 30. 找出最小的K个数 31. 连续子数组的最大和 32. 从1到整数n中1出现的次数 33. 把数组中的数排成一个最小的数 34. 求第N个丑数 35. 第一个出现一次的字符 36. 数组中逆序对的个数 37. 两个链表的第一个公共节点 38. 数字在排序数组中出现的次数 39. 二叉树的深度 40. 数组中只出现一次的两个数,而其他数都出现两次 41. 和为s的连续整数序列 42. 翻转字符串 43. n个骰子的点数及出现的概率 44. 扑克牌的顺子 45. 圆圈中最后剩下的数 46. 1+2+3+...+n的和 47. 不用加减乘除做加法 48. 不能被继承的类 49. 字符串转换为整数 50. 树中两个节点的最低公共祖先 51. 找出重复的数 52. 构建乘积数组 53. 正则表达式匹配 54. 表示数的字符串 55. 字符流中第一个不重复的字符 56. 链表中环的入口节点 57. 删除链表中重复的节点 58. 二叉树的下一个节点 59. 对称的二叉树 60. 按之字形顺序打印二叉树 61. 把二叉树打印成多行 62. 序列化二叉树 63. 二叉搜索树的第K个节点 64. 数据流中的中位数 65. 滑动窗口的最大 66. 矩阵中的路径 67. 机器人的运动范围
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值