Leetcode刷题笔记(持续更新 2021.4.9)

题目1:数组中重复的数

找出数组中重复的数字。


在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

示例 1:

输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3 
 

限制:

2 <= n <= 100000

开始的第一反应的暴力破解,想着从第一个数开始逐个进行比较,程序如下,然而无奈超时了

int findRepeatNumber(int* nums, int numsSize){
    int i=0,j=1;
    while(nums[i]!=nums[j])
    {
        j++;
        if(j==numsSize)
        {
            i=i+1;
            j=i+1;
        }

    }
    return nums[i];
}

        然后根据网上的思路,做出了修改,题目已经说明了,数组中的数字都在0`n-1范围内,不妨初始化一个大小为n的数组,将每个值初始化为-1,在依次遍历nums数组中的每个数字,并将其值作为数组的下标,如果该地址下的值是-1说明是第一次出现,将该处的值设置为一个不为-1的数;如果该地址下的值不是-1说明是第二次出现,直接返回该值即可。该方法虽然不是最简单的,却是比较容易想到的。

int findRepeatNumber(int* nums, int numsSize){
    int array1[numsSize];
    int i;
    for(i=0;i<numsSize;i++)
    {
        array1[i]=-1;
    }
    for(i=0;i<numsSize;i++)
    {
        if(array1[nums[i]]!=-1)
        {
            return nums[i];
        }
        else
        {
            array1[nums[i]]=i;
        }
    }
    return 0;
}

 

题目2:替换空格

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

示例 1:

输入:s = "We are happy."
输出:"We%20are%20happy."
 

限制:

0 <= s 的长度 <= 10000

          这个很简单,先遍历一遍字符,确定字符串长度(如果检测到空格,长度多加2),然后申请一段动态内存,再一次检测字符中的空格,并用‘%20’替代即可。

char* replaceSpace(char* s){
    int len=1;
    int i=0;
    int j;
    for(j=0;s[j]!='\0';j++) //检测终止符
    {
        if(s[j]==0x20)
        {
            len=len+3;
        }
        else
        {
            len=len+1;
        }
    }
   
    char *result=(char*)calloc(len,sizeof(char));
    
    while(*s!='\0')
    {
        if(*s==0x20)
        {
            result[i++]='%';
       
            result[i++]='2';
      
            result[i++]='0';
        }
        else
        {
            result[i++] = *s;
        }
        
        s++;
 
    }
    result[i] ='\0';
    return result;
}

 

题目3:从尾到头打印链表

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

示例 1:
输入:head = [1,3,2]
输出:[2,3,1]
 

限制:

0 <= 链表长度 <= 10000

采用迭代即可

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
void reverse(struct ListNode* head,int *result,int *len);
int* reversePrint(struct ListNode* head, int* returnSize){
    int *result=malloc(10000 * sizeof(int));
    
    int length=0;
    reverse(head,result,&length);
    returnSize[0] = length;
    return result;
}

void reverse(struct ListNode* head,int *result,int *len)
{
    if(!head) return;
    reverse(head->next,result,len);
    result[*len]=head->val;
    *len=*len+1;
}

题目4:二进制中1的个数

请实现一个函数,输入一个整数(以二进制串形式),输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。

示例 1:

输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。
示例 2:

输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。
示例 3:

输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。
 

提示:

输入必须是长度为 32 的 二进制串 。

 思路很简单:不断向右移位,并判断其是否能被2整除,可以说明最后一位是0,否则为1。

int hammingWeight(uint32_t n) {
    int cnt=0;
    int i;
    for(i=0;i<32;i++)
    {
        if(n%2!=0)
        {
            cnt=cnt+1;
        }
        n=n>>1;
    }
    return cnt;
}

题目5:重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

例如,给出

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7
 

限制:

0 <= 节点个数 <= 5000

前序遍历的第一个值为整个树的根节点,接着再中序遍历中找到该节点,并将中序遍历一分为三。

将大小为num的部分看作一个一个整体作为左子树,将大小为all-num-1的部分看作一个一个整体作为右子树,其结构如下:

接着,对左子树进行分析。同样的道理对其进行分解,如下:

左子树前序遍历的第一个值依旧为根节点,按照上述的分解方法,得出的最新结构如下:

                                                                                                                                         。。。

右子树按照同样的方法分解。左右子树进行迭代,直到子树的值为。其程序如下:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize){
    if(preorderSize==0) return NULL;
    int num=preorderSize;
 
    struct TreeNode* Node=malloc(sizeof(struct TreeNode));
    Node->val=preorder[0];
    while(num--)
    {
        if(inorder[num]==preorder[0])
        {
            break;
        }
    }
    
    Node->left=buildTree(preorder+1,num,inorder,num);
    Node->right=buildTree(preorder+num+1,all-num-1,inorder+num+1,all-num-1);
    return Node;
}

题目6:斐波那契数列 

 第一反应,当然是用迭代求解啦,几行代码就能搞定,但是无奈超时了,就选择了循环求解

int fib(int n){
    /*if(n==0) return 0;
    else if(n==1) return 1;
    else
    {
        return fib(n-1) + fib(n-2);
    }*/
        int f0=0,f1=1;
    int f2,i;
    int f=1e9+7;
    if(n==0)
    {
        return f0;
    }
    else if(n==1)
    {
        return f1;
    }
    else
    {
        for(i=1;i<n;i++)
        {
            f2=(f0+f1)%f;
            f0=f1;
            f1=f2;
        }
        return f2;
    }

 }

题目7:矩阵中的路径

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。

[["a","b","c","e"],
["s","f","c","s"],
["a","d","e","e"]]

但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。

 

示例 1:

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true
示例 2:

输入:board = [["a","b"],["c","d"]], word = "abcd"
输出:false
 

提示:

1 <= board.length <= 200
1 <= board[i].length <= 200

 深度优先搜索,先确定第一个字母的位置,找到了再在该位置的上下左右(注意不能越界)查找第二个字母,依次类推,若中间某个字母未查找到,则再找第一个字母的下一个位置。

bool dfs(char** board, int boardSize, int* boardColSize, char* word,int row,int col,int len)
{
    判断当前位置处的字母是否和word位置处的字母相等 且 不能越界
    if(row < 0 || col < 0 || row >= boardSize || col >= *boardColSize || board[row][col] != word[len])  
    {
        return false;
    }
    //当所有字母都查找完了 则成功
    if(strlen(word)-1==len)
    {
        return true;
    }
    //标记 防止重复查找 避免对连续相同的两个字母产生误判
    char tmp=board[row][col];
    board[row][col]='/';
    bool res=dfs(board,boardSize,boardColSize,word,row+1,col,len+1)||
             dfs(board,boardSize,boardColSize,word,row,col+1,len+1)||
             dfs(board,boardSize,boardColSize,word,row-1,col,len+1)||
             dfs(board,boardSize,boardColSize,word,row,col-1,len+1);
    board[row][col] = tmp;
    return res;
}
bool exist(char** board, int boardSize, int* boardColSize, char* word){
    int i,j;
    for(i=0;i<boardSize;i++)
    {
        for(j=0;j<* boardColSize;j++)
        {
            if(dfs(board,boardSize,boardColSize,word,i,j,0))
            {
                return true;
            }
        }
    }
    return false;
}

 

 

 

题目8:机器人的运动范围

直接用深度优先搜索即可,从位置(0,0)开始,每次可走上下左右四个方向(注意不要越界),且每次都将经过的位置做标记,防止路径重复,当当前位置符合数位和条件且未被标记时,可接着向上下左右四个方向进行行进,否则返回。
int total_way = 0; //记录总的路径数
//求数位和
int sum(int m, int n)
{
	int a = 0;
	int i1, j1, k1, i2, j2, k2;
	i1 = m / 100;
	j1 = (m % 100) / 10;
	k1 = (m % 100) % 10;

	i2 = n / 100;
	j2 = (n % 100) / 10;
	k2 = (n % 100) % 10;

	return i1 + i2 + j1 + j2 + k1 + k2;

}
//深度优先搜索遍历
void dfs(char **visited,int m, int n, int k,int now_m,int now_n)
{
    //没有越界且数位和小于等于k
	if ((now_m >= 0) && (now_n >= 0) && (now_n <= n) && (now_m <= m) && (sum(now_m, now_n) <= k))
	{
		if (visited[now_m][now_n] != 1) //如果该位置未被访问过,则标记
		{
			visited[now_m][now_n] = 1;
		}
		else
		{
			return;
		}
	}
	else
	{
		return;
	}
	

	total_way = total_way + 1;
	dfs(visited,m, n, k, now_m + 1, now_n);
	dfs(visited, m, n, k, now_m, now_n + 1);
	dfs(visited, m, n, k, now_m - 1, now_n);
	dfs(visited, m, n, k, now_m, now_n - 1);
}

int movingCount(int m, int n, int k){

	int i;
    //为二维数组动态分配动态内存
	char **visited = (char **)malloc((m)*sizeof(char *));
	for (i = 0; i < m; i++)
	{
		visited[i] = (char *)malloc((n)*sizeof(char));
        
	}
	total_way = 0;	
    //实际计算时 下标都是从0开始
	m = m - 1;
	n = n - 1;
	dfs(visited, m, n, k, 0, 0);

	for (i = 0; i < m; i++)
	{
		free(visited[i]);/*释放列*/
	}	
	free(visited);/*释放行*/

	

	return total_way;
}

题目9:旋转数组的最小数字

 

因为这个数组中的数可以看作有序数,所有可以先假定第一个数最小,然后遍历,如果后续遇到了比这个数还小的数,则此数是最小数,否则第一个数为最小数

int minArray(int* numbers, int numbersSize){
    int i;
    for(i=1;i<numbersSize;i++)
    {
        if(numbers[0]>numbers[i])
        {
            return numbers[i];
        }
    }
    return numbers[0];
}

题目10:青蛙跳台阶问题

一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

示例 1:

输入:n = 2
输出:2
示例 2:

输入:n = 7
输出:21
示例 3:

输入:n = 0
输出:1
提示:

0 <= n <= 100

可以·将此问题看作斐波那契数列问题,则解法就同题目6,青蛙的最后一步只有两种情况,跳上一级台阶或跳上两级台阶,设总共有f(n)种跳法:

若跳一级台阶时,则还剩n-1级台阶,此种情况有f(n-1)种跳法;

若跳二级台阶时,则还剩n-2级台阶,此种情况有f(n-2)种跳法;

f(n)是以上两种情况之和,则f(n)=f(n-1)+f(n-2),此时正好是斐波那契数列的性质。程序与题目6相同

题目11:二维数组中的查找

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


示例:

现有矩阵 matrix 如下:

[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。

给定 target = 20,返回 false。

 

限制:

0 <= n <= 1000

0 <= m <= 1000

 最先想到的就是暴力破解,一个数一个数地去遍历:

bool findNumberIn2DArray(int** matrix, int matrixSize, int* matrixColSize, int target)
{
    int i,j;
    for(i=0;i<matrixSize;i++)
    {
        for(j=0;j<* matrixColSize;j++)
        {
            if(matrix[i][j]==target)
            {
                return true;
            }
        }
    }
    return false;
}

       由于数组是个有序的数组,从左到右递增,从上到下递增,可以先确定右上角或者左下角为起始位置,这里,我取的是右上角作起始位置,如果这样向左是递减,向下是递增,如果目标值比该位置处的值大,则向下寻找,比该位置处的值下,则向左寻找,这样保证了每一步都是最优的,程序如下:

bool findNumberIn2DArray(int** matrix, int matrixSize, int* matrixColSize, int target)
{
	int i, j;
	//起始位置,从右上角开始
    i = 0;
	j = *matrixColSize - 1;

    //判断矩阵是否为空
    if (matrix == NULL || matrixSize == 0 || *matrixColSize == 0 )
    {                       
        return false;
    }

	while ((i >= 0) && (j >= 0)&&(i < matrixSize) && (j < *matrixColSize))
	{
        //当前值比目标值大,位置左移,找小的
		if (matrix[i][j]>target)
		{
			j--;
		}
        //当前值比目标值大,位置下移,找大的
		else if (matrix[i][j]<target)
		{
			i++;
		}
        else
		{
			return true;
		}
	}
    return false;
}

测试数据较少,差别不太大,如果数据量大的话,该方法的优势就很明显了。 

题目12:剪绳子

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m-1] 。请问 k[0]*k[1]*...*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

示例 1:

输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
示例 2:

输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
提示:

2 <= n <= 58

 将绳子以相同的长度均分为多段,乘积最大,设每段的长度为x,则乘积为:f(x)=x^{\frac{n}{x}},对它求导求极值点,或者直接画出图像:

可求得当x=e时,该函数值最大,由于只能取整数,且由图像可知f(3)>f(2),所以尽可能地将每段的长度限定在3。

int cuttingRope(int n){
    int a=n/3; //n里面包含多少个3
    int b=n%3; 
    if(n==2) return 1;
    else if(n==3) return 2;
    else
    {
        if(b==0) return pow(3,a);
        else if(b==1) return pow(3,a-1)*2*2;
        else return pow(3,a)*2;
    }
}

题目13:剪绳子||

 

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m - 1] 。请问 k[0]*k[1]*...*k[m - 1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

 

示例 1:

输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
示例 2:

输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
 

提示:
2 <= n <= 1000

 本题与上一题基本一致,只不过n值较大,为了防止溢出,结果要取模。

int cuttingRope(int n){
    int a=n/3; //n里面包含多少个3
    int b=n%3; 
    unsigned long long result=1;
    if(n==2) return 1;
    else if(n==3) return 2;
    else
    {
        if(b==0) 
        {
            while(a--)
            {
                result=result*3;
                result=result%1000000007;
            }
            return result;
        }
        else if(b==1)
        {
            a=a-1;
            result=result*4;
            while(a--)
            {
                result=result*3;
                result=result%1000000007;
            }
            return result;
        } 
        else
        {
            result=result*2;
            while(a--)
            {
                result=result*3;
                result=result%1000000007;
            }
            return result;           
        } 
    }
}

 

题目14:打印从1到最大的n位数

 

 

输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。

示例 1:

输入: n = 1
输出: [1,2,3,4,5,6,7,8,9]
 

说明:

用返回一个整数列表来代替打印
n 为正整数

用pow函数,找到最大的n位数,秒解

class Solution {
public:
    vector<int> printNumbers(int n) {
        vector<int> res;
        int i;
        for(i=1;i<pow(10,n);i++)
        {
            res.push_back(i);
        }
        return res;
    }
};

题目15:删除链表的节点

 
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。

返回删除后的链表的头节点。

注意:此题对比原题有改动

示例 1:

输入: head = [4,5,1,9], val = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
示例 2:

输入: head = [4,5,1,9], val = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
 

说明:

题目保证链表中节点的值互不相同
若使用 C 或 C++ 语言,你不需要 free 或 delete 被删除的节点
 

采用递归的方法

class Solution {
public:
    ListNode* deleteNode(ListNode* head, int val) {
        if(head->val == val)
        {
            return head->next;
        }
        head->next=deleteNode(head->next, val);
        return head;
    }
};

 

题目16:删调整数组顺序使奇数位于偶数前面

 

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。


示例:

输入:nums = [1,2,3,4]
输出:[1,3,2,4] 
注:[3,1,2,4] 也是正确的答案之一。
 

提示:

1 <= nums.length <= 50000
1 <= nums[i] <= 10000

方法简单粗暴,分别找出所有的奇数和偶数,然后再依次插入到数组中。

class Solution {
public:
    vector<int> exchange(vector<int>& nums) {
        vector<int> odd;
        vector<int> even;
        vector<int> result;
        for(int i=0;i<nums.size();i++)
        {
            if(nums[i]%2==0)
            {
                even.push_back(nums[i]);
                //result.insert(result.end(), nums[i]);
            }
            else
            {
                //result.insert(result.begin(), nums[i]);
                odd.push_back(nums[i]);
            }
        }
        int i1=odd.size();
        result.insert(result.begin(),odd.begin(),odd.end());
        result.insert(result.begin()+i1,even.begin(),even.end());
        return result; 
    }
};

消耗的内存有点大,但是时间还好。

题目17:链表中倒数第k个节点

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。

例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。


示例:

给定一个链表: 1->2->3->4->5, 和 k = 2.

返回链表 4->5.

 看了题解,可以用快慢指针解决此类问题,上一题也可用此方法。核心就是定义两个指针,一个快指针,一个慢指针,在本题中,快指针比慢指针走快k步,当快指针到达链尾时,慢指针就指向了链表尾节点的倒数第k个节点。【ps:上一题也可以用此思路,快指针去判断是否为奇数,慢指针指向下一个奇数应该存放的位置】

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* getKthFromEnd(ListNode* head, int k) {
        ListNode* fast=head;
        for(int i=0;i<k;i++)
        {
            fast=fast->next;
        }
        while(fast)
        {
            fast=fast->next;
            head=head->next;
        }
        return head;
    }
};

 

题目18:合并两个排序的链表

 

 

输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。

示例1:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
限制:

0 <= 链表长度 <= 1000

使用双指针l1和12遍历两个链表,根据l1.val和l2.val的值确定两个节点的添加顺序,直至某一方遍历完成

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* head = new ListNode(1); //初始化一个节点值为1的空节点
        ListNode* ret = head;

        while((l1!=NULL)&&(l2!=NULL))
        {
            if((l1->val) < (l2->val))
            {
                head->next=l1;
                l1=l1->next;
            }
            else
            {
                head->next=l2;
                l2=l2->next;
            }
            head=head->next;
        }
        if(l1==NULL)
        {
            head->next=l2;
        }
        else if(l2==NULL)
        {
            head->next=l1;
        }
        return ret->next;
    }
};

 

题目19:顺时针打印矩阵

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。


示例 1:

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
示例 2:

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
 

限制:

0 <= matrix.length <= 100
0 <= matrix[i].length <= 100

 可以分层打印,先打印最外圈,再打印次外圈,定义上下左右四个边界进行遍历【注意边界值相等时的处理】

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        
        if (matrix.size() == 0 || matrix[0].size() == 0) 
        {
            return {};
        }

        vector<int> res;
        int rows = matrix.size(),columns = matrix[0].size();

        int left = 0, right = columns - 1, top = 0, bottom = rows - 1;
        int now_row,now_col;
        while(left<=right && top<=bottom)
        {
            now_row=top;
            for(now_col=left;now_col<=right;now_col++)
            {
                res.push_back(matrix[now_row][now_col]);
            }

            
            now_col=right;
            for(now_row=top+1;now_row<=bottom;now_row++)
            {
                res.push_back(matrix[now_row][now_col]);
            }  

            if(top!=bottom && left!=right)
            {
                now_row=bottom;
                for(now_col=right-1;now_col>=left;now_col--)
                {
                    res.push_back(matrix[now_row][now_col]);
                }

                now_col=left;
                for(now_row=bottom-1;now_row>top;now_row--)
                {
                    res.push_back(matrix[now_row][now_col]);
                }  
            }
 

            left++;
            right--;
            top++;
            bottom--;

        }
        
        return res;
    }
};

题目20:二叉树的镜像

请完成一个函数,输入一个二叉树,该函数输出它的镜像。

例如输入:

     4
   /   \
  2     7
 / \   / \
1   3 6   9
镜像输出:

     4
   /   \
  7     2
 / \   / \
9   6 3   1

 

示例 1:

输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]
 

限制:

0 <= 节点个数 <= 1000 

采用递归法   模型:二叉树的先序遍历(遍历二叉树的所有结点)  递归返回条件:当前结点为 NULL   实现操作:交换根结点的左右子树

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* mirrorTree(TreeNode* root) {
       if(root==NULL) return NULL;
       swap(root->left,root->right);
       mirrorTree(root->left);
       mirrorTree(root->right);
  
       return root;
    }
};

题目21:对称的二叉树

请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

    1
   / \
  2   2
 / \ / \
3  4 4  3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:

    1
   / \
  2   2
   \   \
   3    3

 

示例 1:

输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:

输入:root = [1,2,2,null,3,null,3]
输出:false
 

限制:

0 <= 节点个数 <= 1000

采用递归。判断左子树的左子树和右子树是右子树,左子树的右子树和右子树是左子树是否相等

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool compare(TreeNode* left,TreeNode* right)
    {
        if(left==NULL && right==NULL) return true;
        else if(left==NULL && right!=NULL) return false;
        else if(left!=NULL && right==NULL) return false;
        else if (left->val != right->val) return false;
  

        bool res1 = compare(left->left,right->right);
        bool res2 = compare(left->right,right->left);
        bool isSame = res1 && res2; 
        return isSame;
    }

    bool isSymmetric(TreeNode* root) {
        if(root==NULL) return true;
        return compare(root->left,root->right);
    }
};

 

题目22:树的子结构

输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)

B是A的子结构, 即 A中有出现和B相同的结构和节点值。

例如:
给定的树 A:

     3
    / \
   4   5
  / \
 1   2
给定的树 B:

   4 
  /
 1
返回 true,因为 B 与 A 的一个子树拥有相同的结构和节点值。

示例 1:

输入:A = [1,2,3], B = [3,1]
输出:false
示例 2:

输入:A = [3,4,5,1,2], B = [4,1]
输出:true
限制:

0 <= 节点个数 <= 10000

 可以现在A中找B的根节点的值,如果A==NULL时或者B==NULL时,则B不是A的子结构;若找到,再进一步判断A的左右子树和B的左右子树是不是相等。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool scan(TreeNode* A,TreeNode* B)
    {
        if(B==NULL) return true;  //当B为空说明B匹配完成
        else if((A==NULL)||(A->val != B->val)) return false; //当A为空说明已经越过树A叶子节点,即匹配失败或者当两个值不等时,也匹配失败
        return scan(A->left,B->left)&&scan(A->right,B->right);
    }

    bool isSubStructure(TreeNode* A, TreeNode* B) {
        if(A==NULL || B==NULL) return false;
        return scan(A,B)||(isSubStructure(A->left,B))||(isSubStructure(A->right,B)); 
        
    }

};

 

题目23:从上到下打印二叉树

 

从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。

 

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回:

[3,9,20,15,7]
 

提示:

节点总数 <= 1000

可以采用层序遍历的方法,将二叉树的根结点放入队列,当队列为空时跳出,当队列不为空时,将队头处的值放入容器中,并分别将左右子树入队(左右子树不为空),并将队头出队,下一次循环中,前一次的左子树为队头,重复上述操作。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> levelOrder(TreeNode* root) {
        vector<int>res;
		queue<TreeNode *>q;//辅助队列
        if(root==NULL) return res;
        else q.push(root);

        while(!q.empty())
        {
            res.push_back(q.front()->val);
            if(q.front()->left!=NULL) q.push(q.front()->left);
            if(q.front()->right!=NULL) q.push(q.front()->right);
            q.pop(); 
        }
        return res;
    }
};

 

题目24:从上到下打印二叉树2

从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

 

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回其层次遍历结果:

[
  [3],
  [9,20],
  [15,7]
]

与上题类似,只不过此题要加个计数器,数值为本层的节点数。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        queue<TreeNode *>q;//辅助队列
        if(root==NULL) return res;
        else q.push(root);
        while(!q.empty())
        {
            vector<int> temp;
            int cnt = q.size();   // 当前层的节点数
            
            while(cnt)
            {
                temp.push_back(q.front()->val);
                if(q.front()->left!=NULL) q.push(q.front()->left);
                if(q.front()->right!=NULL) q.push(q.front()->right);
                q.pop();
                
                cnt--; 
            }
            res.push_back(temp);
        }
        return res;
    }
};

题目25:从上到下打印二叉树3

 
请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

 

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回其层次遍历结果:

[
  [3],
  [20,9],
  [15,7]
]
 

提示:

节点总数 <= 1000

 与上题类似,只是加一个计数器,使结果满足条件后反转。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        queue<TreeNode *>q;//辅助队列
        if(root==NULL) return res;
        else q.push(root);
        int num=0;
        while(!q.empty())
        {
            vector<int> temp;
            int cnt=q.size();
            while(cnt)
            {
                temp.push_back(q.front()->val);
                if(q.front()->left!=NULL) q.push(q.front()->left);
                if(q.front()->right!=NULL) q.push(q.front()->right);
                q.pop();               
                cnt--;
            }
            if(num%2!=0) 
            {
                reverse(temp.begin(), temp.end());
            }
            num++;
            res.push_back(temp);
        }
        return res;
    }
};

题目26:二叉搜索树与双向链表

 

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。


为了让您更好地理解问题,以下面的二叉搜索树为例:
 

我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。

下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。

 

特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。

很容易看出,二叉搜索树的中序遍历就是从小到大的排序的结果。

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* left;
    Node* right;

    Node() {}

    Node(int _val) {
        val = _val;
        left = NULL;
        right = NULL;
    }

    Node(int _val, Node* _left, Node* _right) {
        val = _val;
        left = _left;
        right = _right;
    }
};
*/
class Solution {
public:
    Node* treeToDoublyList(Node* root) {
       if(root == NULL) return nullptr;
        dfs(root);
        head->left = pre;
        pre->right = head;
        return head;
    }
private:
    Node* head;
    Node* pre;
    void dfs(Node* cur)
    {
        if(cur==NULL) return;
        dfs(cur->left);
        if(pre==NULL) head=cur;
        else pre->right = cur;
        cur->left=pre;
        pre=cur;
        dfs(cur->right);
    }
};

题目27:二数组中出现次数超过一半的数

 

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

 

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

 

示例 1:

输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2
 

限制:

1 <= 数组长度 <= 50000

采用摩尔投票法找众数。

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        /*unordered_map <int,int> mp;
        for(int n:nums)
        {
            if(++mp[n]>nums.size()/2)  return n;
        }
        return 0;*/
        int res=nums[0],votes=0;
        for(auto num:nums)
        {
            if(num==res) votes++;
            else votes--;
            if(votes<=0) 
            {
               res=num;
               votes=1;
            }

        }
        return res;
    }
};

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨狼007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值