剑指 Offer 16. 数值的整数次方
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。
示例 1:
输入:x = 2.00000, n = 10
输出:1024.00000
示例 2:
输入:x = 2.10000, n = 3
输出:9.26100
示例 3:
输入:x = 2.00000, n = -2
输出:0.25000
解释:2-2 = 1/22 = 1/4 = 0.25
求 x^nx
n
最简单的方法是通过循环将 nn 个 xx 乘起来,依次求 x^1, x^2, …, x^{n-1}, x^nx
,时间复杂度为 O(n)O(n) 。
快速幂法 可将时间复杂度降低至 O(log_2 n)O(log
2
2的5次方=2*4的平方
class Solution {
public double myPow(double x, int n) {
if(x==0) return 0;
double res=1;
long b=n;
if(b<0){
x=1/x;
b=-b;
}
while(b>0){
if((b&1)==1)res*=x;
x*=x;
b>>=1;
}
return res;
}
}
剑指 Offer 17. 打印从1到最大的n位数
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
示例 1:
输入: n = 1
输出: [1,2,3,4,5,6,7,8,9]
class Solution {
public int[] printNumbers(int n) {
int b=1;
while(n>0){
b*=10;
n--;
}
int[] res =new int[b-1];
for(int i=0;i<b-1;i++)
{
res[i]=i+1;
}
return res;
}
}
应考虑大数运算,使用全排列来解。
剑指 Offer 18. 删除链表的节点
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
返回删除后的链表的头节点。
注意:此题对比原题有改动
示例 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.
//双指针来实现遍历链表
public ListNode deleteNode(ListNode head, int val) {
if(head.val==val)return head.next;
ListNode pre=head,cur=head.next;
while(cur.val!=val&&cur!=null){
pre=cur;cur=cur.next;
}
if(cur!=null) pre.next=cur.next;
return head;
}
剑指 Offer 20. 表示数值的字符串
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
数值(按顺序)可以分成以下几个部分:
若干空格
一个 小数 或者 整数
(可选)一个 ‘e’ 或 ‘E’ ,后面跟着一个 整数
若干空格
小数(按顺序)可以分成以下几个部分:
(可选)一个符号字符(’+’ 或 ‘-’)
下述格式之一:
至少一位数字,后面跟着一个点 ‘.’
至少一位数字,后面跟着一个点 ‘.’ ,后面再跟着至少一位数字
一个点 ‘.’ ,后面跟着至少一位数字
整数(按顺序)可以分成以下几个部分:
(可选)一个符号字符(’+’ 或 ‘-’)
至少一位数字
部分数值列举如下:
["+100", “5e2”, “-123”, “3.1416”, “-1E-16”, “0123”]
部分非数值列举如下:
[“12e”, “1a3.14”, “1.2.3”, “±5”, “12e+5.4”]
示例 1:
输入:s = “0”
输出:true
示例 2:
输入:s = “e”
输出:false
示例 3:
输入:s = “.”
输出:false
示例 4:
输入:s = " .1 "
输出:true
有限状态自动机
剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数在数组的前半部分,所有偶数在数组的后半部分。
示例:
输入:nums = [1,2,3,4]
输出:[1,3,2,4]
注:[3,1,2,4] 也是正确的答案之一。
class Solution {
public int[] exchange(int[] nums) {
if(nums.length==0)return nums;
int i=0,j=nums.length-1;
while(true){
while((nums[i]&1)!=0&&i<nums.length-1)i++;
while(j>=0&&(nums[j]&1)==0)j--;
if(i<j){
int temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
}
else break;
}
return nums;
}
}
双指针实现,注意数组越界问题。特殊情况,当输入数组全为奇数或者全为偶数时。
剑指 Offer 22. 链表中倒数第k个节点
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。
例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。
示例:
给定一个链表: 1->2->3->4->5, 和 k = 2.
返回链表 4->5.
public ListNode getKthFromEnd(ListNode head, int k) {
int count=0;
ListNode temp=head;
while(temp!=null){
count++;
temp=temp.next;
}
int n=count-k;
while(n>0){
head=head.next;
n--;
}
return head;
}
思路二:不需要知道链表长度,指针1先走k-1步,然后指针2和指针1同时前进,当指针1指向链表最后一个元素时,指针2即为所求。
剑指 Offer 24. 反转链表
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
public ListNode reverseList(ListNode head) {
ListNode cur=head,pre=null,temp;
while(cur!=null){
temp=cur.next;
cur.next=pre;
pre=cur;
cur=temp;
}
return pre;
}
注意结束条件的判断和双指针的使用
剑指 Offer 25. 合并两个排序的链表
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
示例1:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode res=new ListNode(0),dum=res;
while(l1!=null&&l2!=null)
{
if(l1.val<=l2.val){
res.next=l1;
l1=l1.next;
}
else {
res.next=l2;
l2=l2.next;
}
res=res.next;
}
res.next=l1!=null?l1:l2;
return dum.next;
}
剑指 Offer 26. 树的子结构
输入两棵二叉树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
感觉树的很多递归题,想清楚如何分解为子问题就好做了,函数内调用递归函数不要太纠结细节,清楚函数的功能就行
public boolean isSubStructure(TreeNode A, TreeNode B) {
if(A==null||B==null)
return false;
return contains(A,B)||isSubStructure(A.left,B)||isSubStructure(A.right,B);
}
public boolean contains(TreeNode A,TreeNode B)
{
if(B==null)return true;
if(A==null||A.val!=B.val)return false;
return contains(A.left,B.left)&&contains(A.right,B.right);
}
剑指 Offer 27. 二叉树的镜像
请完成一个函数,输入一个二叉树,该函数输出它的镜像。
根据二叉树镜像的定义,考虑递归遍历(dfs)二叉树,交换每个节点的左 / 右子节点,即可生成二叉树的镜像。
//递归
public TreeNode mirrorTree(TreeNode root) {
if(root==null)return null;
TreeNode temp=root.left;
root.left=mirrorTree(root.right);
root.right=mirrorTree(temp);
return root;
}
//使用辅助栈完成反转
public TreeNode mirrorTree(TreeNode root) {
if(root==null)return null;
Stack<TreeNode> stack=new Stack<>();
stack.add(root);
while(stack.size()!=0){
TreeNode a=stack.pop();
if(a.left!=null)stack.push(a.left);
if(a.right!=null)stack.push(a.right);
TreeNode temp=a.left;
a.left=a.right;
a.right=temp;
}
return root;
}