剑指Offer算法精炼

Posted WQP_Ya_Ping

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指Offer算法精炼相关的知识,希望对你有一定的参考价值。

//FileName :: Algorithm.cpp(剑指Offer)
//Author   :: Weiqp
//Date     :: 2016-6-14

/*1. 输出链表倒数第K个节点
    思想:使用两个指针p1,p2,起初同时指向链表头节点,先让p1向前走K-1步,然后两个指针同时向后移动,
    当p1指向链表末尾,即p1->next为空时,p2此时正好指向倒数第K个节点
*/
# if 0
# include <iostream>
using namespace std;

//链表节点定义
typedef struct ListNode

    int value;
    ListNode *next;
;

//查找倒数第K个节点
ListNode* FindKthToTail(ListNode *head, unsigned int k)

    //安全性检查
    if(head == NULL || k == 0)
    
        return NULL;
    
    ListNode *p1 = head;
    ListNode *p2 = NULL;

    for(unsigned int i = 0; i < k-1; i++)
    
        //检查K是否大于链表的实际长度
        if(p1 ->next != NULL)
        
            p1 = p1 ->next ;
        
        else
        
            return NULL;
        
    

    ListNode *p2 = head;
    while(p1 ->next != NULL)
    
        p1 = p1 ->next ;
        p2 = p2 ->next ;
    

    return p2;

# endif

/*2. 链表反转
    思想:三个指针,分别指向当前节点、前一个和后一个节点。
*/
# if 0
# include <iostream>
using namespace std;

//链表节点定义
typedef struct ListNode

    int value;
    ListNode *next;
;

//反转
ListNode* ReverseList(ListNode *head)

    ListNode* pReverseHead = NULL;
    ListNode* pNode = head;
    ListNode* pPrev = NULL;

    while(pNode != NULL)
    
        ListNode* pNext = pNode ->next ;
        if(pNext == NULL)
        
            pReverseHead = pNode;
        
        else
        
            pNode ->next = pPrev;
        
        //往后依次反转
        pPrev = pNode;
        pNode = pNode ->next ;
    
    return pReverseHead;

# endif

/*3. 合并两个有序链表
    思想:先比较两个链表的第一个节点的值value1和value2,如果value1小,则它作为合并后链表的头节点,
    接着比较value1节点的next->value和value2,,小的作为合并头节点的next,依次进行。否则反之。
*/
# if 0
# include <iostream>
using namespace std;

//链表节点定义
typedef struct ListNode

    int value;
    ListNode *next;
;

//合并
ListNode * MergeList(ListNode *head1, ListNode *head2)

    if(head1 == NULL && head2 == NULL)
    
        return NULL;
    
    else if(head1 != NULL)
    
        return head1;
    
    else
    
        return head2;
    

    ListNode* pMergeHead = NULL;
    if(head1 ->value >= head2 ->value )
    
        pMergeHead = head2;
        pMergeHead ->next = MergeList(head1, head2 ->next);
    
    else
    
        pMergeHead = head1;
        pMergeHead ->next = MergeList(head1 ->next , head2);
    

    return pMergeHead;

# endif

/*4.判断B树是不是A树的子结构*/
# if 0
# include <iostream>
using namespace std;

//二叉树节点定义
typedef struct BinaryTree

    int value;
    BinaryTree* left;
    BinaryTree* right;
;

//是否有B结构的树
bool IsTree1HaveTree2(BinaryTree* root1, BinaryTree* root2)

    if(root2 == NULL)
    
        return true;
    
    if(root1 == NULL)
    
        return false;
    
    //以root1为根节点的树无子结构Tree2
    if(root1 ->value != root2 ->value )
    
        return false;
    

    return IsTree1HaveTree2(root1 ->left , root2 ->left ) && 
        IsTree1HaveTree2(root1 ->right , root2 ->right );


bool HasSubTree(BinaryTree* root1, BinaryTree* root2)

    bool result = false;

    if(root1 != NULL && root2 != NULL)
    
        if(root1 ->value == root2 ->value )
        
            result = IsTree1HaveTree2(root1, root2);
        
        if(!result)
        
            result = HasSubTree(root1 ->left ,root2);
        
        if(!result)
        
            result = HasSubTree(root1 ->right ,root2);
        
    
    return result;

# endif

/*5.求一个树的镜像
    思想::交换子节点
*/
# if 0
# include <iostream>
using namespace std;

//二叉树节点定义
typedef struct BinaryTree

    int value;
    BinaryTree* left;
    BinaryTree* right;
;

void MirrorRecursively(BinaryTree* p)

    if((p == NULL) ||(p ->left == NULL && p ->right == NULL))
    
        return ;
    
    BinaryTree* temp = p->left ;
    p ->left = p ->right ;
    p ->right = temp;

    if(p ->left)
    
        MirrorRecursively(p ->left );
    
    if(p ->right )
    
        MirrorRecursively(p ->right );
    

# endif

/*6.顺时针打印方阵
    思想:从外圈向内圈一圈一圈的打印,每一圈的打印步骤为:从左到右打印一行,从上往下打印一列,
    从右往左打印一行,从下往上打印一列(注意避免重复打印)。假设最后一圈左上角坐标为(startX, startY),
    则终止条件是::列数columns > startX * 2; 行数rows > startY * 2;
*/
# if 0
# include <iostream>
using namespace std;

//一圈的打印过程
void PrintMatrixInCircle(int **numbers, int columns, int rows, int start);

//循环打印矩阵
void PrintMatrixClockWisely(int **numbers, int columns, int rows)

    if(NULL == numbers || columns <= 0 || rows <= 0)
    
        return ;
    

    int start = 0;//第一圈左上角坐标
    while(columns > start * 2 && rows > start * 2)
    
        PrintMatrixInCircle(numbers, columns, rows, start);
        start ++;
    


//一圈的打印过程
void PrintMatrixInCircle(int **numbers, int columns, int rows, int start)

    //每圈的右下角坐标
    int endX = columns - 1 - start;
    int endY = rows - 1 - start;

    //从左到右
    for(int i = start; i <= endX; i++)
    
        int number = numbers[start][i];
        cout<<number<<"  ";
    
    //从上到下
    if(start < endY)
    
        for(int i = start + 1; i < endY; i++)
        
            int number = numbers[i][endX];
            cout<<number<<"  ";
        
    
    //从右到左
    if(start < endX && start < endY)
    
        for(int i = endX - 1; i >= start; i--)
        
            int number = numbers[endY][i];
            cout<<number<<"  ";
        
    
    //从下到上
    if(start < endX && start < endY - 1)
    
        for(int i = endY - 1; i >= start + 1; i--)
        
            int number = numbers[i][start];
            cout<<number<<"  ";
        
    

# endif
/*7.打印蛇形矩阵*/
# if 0
#include<stdio.h>

int row,col;
int matrix[100][100]=0;
void UpFillNum(int);
void DownFillNum(int);

int main()

  int n;
  int i,j;
  printf("请输入矩阵的阶数:(0<n<=100)");
  scanf("%d",&n);
  matrix[0][0]=1;
  matrix[1][0]=2;
  row=1;
  col=0;
  UpFillNum(n-1);
  for(i=0;i<n;i++)
  
    for(j=0;j<n;j++)
    
    printf("%d ",matrix[i][j]);
    
    printf("\\n");
  
  return 0;


//从上向下填充
void DownFillNum(int n)

  for(;col>0 && row<n;row++,col--)
    matrix[row+1][col-1]=matrix[row][col]+1;
  if(row<n)
  
    row++;
    matrix[row][col]=matrix[row-1][col]+1;
  
  else if(row==n)
  
    col++;
    matrix[row][col]=matrix[row][col-1]+1;
  
  if(matrix[n][n]!=((n+1)*(n+1)))
    UpFillNum(n);


//从下向上填充
void UpFillNum(int n)

  for(;row>0 && col<n;col++,row--)
    matrix[row-1][col+1]=matrix[row][col]+1;
  if(col<n)
  
    col++;
    matrix[row][col]=matrix[row][col-1]+1;
  
  else if(col==n)
  
    row++;
    matrix[row][col]=matrix[row-1][col]+1;
  
  if(matrix[n][n]!=((n+1)*(n+1)))
    DownFillNum(n);

# endif

/*8.包含最小值函数min()的栈
    数据栈::m_data
    辅助栈::m_min,用于保存最小值
*/
# if 0

# include <iostream>
using namespace std;
# include <stack>

//push()
template <typename T> void StackWithMin<T>:: push(const T &value)

    m_data.push(value);

    if(m_min.size() == 0 || value < m_min.top())
    
        m_min.push(value);
    
    else
    
        m_min.push(m_min.top());
    


//pop
template <typename T> void StackWithMin<T>:: pop()

    assert(m_data.size > 0 && m_min.size > 0);

    m_data.pop();
    m_min.pop();

//min()
template <typename T> void StackWithMin<T>:: min() const

    assert(m_data.size > 0 && m_min.size > 0);
    return m_min.top();

# endif

/*9.判断一个序列是不是栈的弹出序列*/
/*
思想::建立一个辅助栈。
比如压栈序列为1,2,3,4,5,,判断序列4,3,5,1,2是不是出栈序列
1.第一个弹出的数是4,,所以依次将1,2,3,4压入辅助栈,此时4位于栈顶可弹出。
2.下一个弹出3,此时辅助栈3位于栈顶,可弹出。
3.下来弹出的是5, 把5压入辅助栈,,位于栈顶,可弹出。
4.此时要求弹出1,因为此时辅助栈剩下1,2,且2位于栈顶。所以无法直接弹出1.
5.所以4,3,5,1,2不是一个弹出序列。
*/

/*10.从上往下打印二叉树*/
# if 0

//二叉树结点定义
/*思想::每次打印一个节点时,将他的子节点放入队列的尾部,从队列头开始打印节点,打印完为止*/
struct BinaryTreeNode

    int            m_value;
    BinaryTreeNode *m_Left;
    BinaryTreeNode *m_Right;
;
//打印
void PrintFromTopToBottom(BinaryTreeNode * pTreeRoot)

    if(!pTreeRoot)
    
        return ;
    
    std::deque<BinaryTreeNode *> dequeTreeNode;

    dequeTreeNode.push_back(pTreeRoot);

    while(dequeTreeNode.size())
    
        BinaryTreeNode *pNode = dequeTreeNode.front();
        dequeTreeNode.pop_front();

        printf("%d ", pNode->m_value );
        if(pNode ->m_Left )
        
            dequeTreeNode.push_back(pNode ->m_Left);
        
        if(pNode ->m_Right )
        
            dequeTreeNode.push_back(pNode ->m_Right );
        
    

# endif

以上是关于剑指Offer算法精炼的主要内容,如果未能解决你的问题,请参考以下文章

算法剑指 Offer 47. 礼物的最大价值

剑指 Offer II 098. 路径的数目

剑指 Offer II 098. 路径的数目

剑指 Offer II 098. 路径的数目

剑指 Offer II 013. 二维子矩阵的和

算法总结:剑指offer(数字查找)