7天刷完剑指offer(二)

题库来源:牛客网

《7天刷完剑指offer》系列只提供解题思路,代码实现见牛客网

数值的整数次方

题目:

思路

解法1: 暴力法。exponent个base相乘,循环exponent次。时间复杂度:O(n),空间复杂度:O(1)

解法2: 快速幂。已知 b a s e e = ( b a s e e 2 ) 2 base^e = (base^{\frac{e}{2}})^2 basee=(base2e)2, 如果e 是偶数。当e是奇数, b a s e e = ( b a s e e 2 ) 2 ∗ b a s e base^e = (base^{\frac{e}{2}})^2 * base basee=(base2e)2base。注意当e是负数的时候, b a s e e = ( 1 b a s e ) − e base^e = (\frac{1}{base})^{-e} basee=(base1)e

1)递归:每次折半递归

2)非递归:利用二进制的特性,假设求 3 9 3^9 39, 9的二进制是1001。则 3 9 = 1 ∗ 3 + 0 ∗ 3 2 + 0 ∗ 3 4 + 1 ∗ 3 8 3^9 = 1 * 3 + 0* 3^2 + 0 * 3^4 + 1 * 3^8 39=13+032+034+138。依次计算 3 , 3 2 , 3 4 , 3 8 3, 3^2, 3^4, 3^8 3,32,34,38, 只有对应的二进制位数是1的时候,把幂加到结果里面。

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

题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

思路

解法1: 暴力解法。创建一个新数组,遍历一遍原数组,把奇数加到新数组里面,然后再遍历一遍,把偶数加进去。把新数组的值赋给原数组。

解法2: in-place,双指针。指针i 表示下一个奇数可以放的位置,指针j 用于获得下一个奇数的值。

指针j的移动方式

  1. 遇到偶数,j++
  2. 遇到奇数,先把[i, j - 1]内的数据整体后移,然后把j位置的数插入到指针i 位置。接着i++。
  3. 直到数据遍历结束

链表中倒数第k个结点

题目:输入一个链表,输出该链表中倒数第k个结点。

思路:快慢指针。两个指针起始指向head, 然后移动快指针k步,接着快慢指针一起移动,直到快指针指向null。 注意,当k > 链表长度,则返回null。

反转链表

题目:输入一个链表,反转链表后,输出新链表的表头。

思路

解法1: 找个中间值存放链表中的节点,比如stack,然后依次反转

解法2: in-place反转。通过pre, curr, nxt三个节点指针,记录反转前后的关系。

pre表示反转后的最后一个节点

curr表示反转前的一个节点

nxt表示curr反转前的下一个节点

nxt = curr.next;

curr.next = pre;

pre = curr;

curr = nxt;

合并两个排序链表

题目:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

思路

解法1: 迭代。新建一个指针head表示合并后链表的头指针,新建一个指针curr表示当前链表上一次合并后的指针。那么curr.next 指向两个链表中较小的节点。然后链表的指针和curr分别指向下一个。

解法2:递归。递归返回的值是当前合并两个链表的头节点。递归的过程如果list1.val ≤ list2.val, 那么list1.next = merge(list1.next, list2)

树的子结构

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

思路:

如果A根节点 = B根节点,判断A的左子树是否等于B的左子树,A的右子树是否等于B的右子树。

如果A根节点 != B根节, 判断B是不是A的左子树的子结构 或者B是不是A的右子树的子结构

public class Solution {
    public boolean HasSubtree(TreeNode root1,TreeNode root2) {
        if(root1 == null || root2 == null) return false;
        
        return root1.val == root2.val && isEqual(root1.left, root2.left) && isEqual(root1.right, root2.right)
                || HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2);

    
        
    }
    public boolean isEqual(TreeNode root1, TreeNode root2){
        if(root2 == null) return true;
        
        if(root1 == null) return false;
        
        return root1.val == root2.val && 
            isEqual(root1.left, root2.left) && isEqual(root1.right, root2.right);
    }

}

二叉树镜像

题目:操作给定的二叉树,将其变换为源二叉树的镜像。

比如:    源二叉树 
            8
           /  \
          6   10
         / \  / \
        5  7 9 11
        镜像二叉树
            8
           /  \
          10   6
         / \  / \
        11 9 7  5

思路

递归,把根节点的左右子树交换一下,交换时用一个临时变量存放其中一个子树。

顺时针打印矩阵

题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

思路

顺时针打印的规律

从左到右打印

从上到下打印

从右到左打印

从下到上打印

然后矩阵往里一圈,继续按照这个规律打印

定义四个变量确定打印范围up, down, left, right

从左到右打印。打印left~ right内的数,打印完up++,表示此行打印完不再使用,同时判断此时up有没有超出down

从上到下打印。打印up~down内的数,打印完right- -, 表示此列不再打印。判断left有没有超出right

从右到左打印。打印right ~ left内的数,打印完down- -, 表示此行不再打印。判断up有没有超出down

从下到上打印。打印down ~ up内的数,打印完left++,表示此列不再打印,判断left有没有超出right。

包含min函数的栈

题目

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

思路:

这道题用Java的Stack类实现栈。利用了Stack类的方法比如

.push():往栈添加元素

.pop():删除栈顶元素,并且返回该元素

.peek():返回栈顶元素,但不删除此元素

.empty():判断栈是否为空

这道题目考察重点是返回栈内最小元素,时间复杂度应为O(1)。元素每次入栈和出栈后都能够获得当前栈的最小元素。因此要借助一个辅助栈来存放最小值。比如

stack = [4, 6, 2, 3]

min_stack = [4, 4, 2, 2]

下一个入栈元素5,5 > min_stack栈顶元素2,则5入栈后,最小的元素还是2。此时

stack = [4, 6, 2, 3, 5]

min_stack = [4, 4, 2, 2, 2]

如果此时5出栈,min_stack对应的2也出栈,此时

stack = [4, 6, 2, 3]

min_stack = [4, 4, 2, 2]

你可能感兴趣的:(算法,算法)