剑指offer刷题笔记(六)
剑指 Offer 42. 连续子数组的最大和
- 输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
贪心法,当相加和为负数而当前数组值为正数时,我们就可以抛弃之前的和,从这个数组重新开始。
class Solution {
public int maxSubArray(int[] nums) {
if(nums.length==0){
return 0;
}
int sum=0;
int maxsum=Integer.MIN_VALUE;
for(int i=0;imaxsum){
maxsum=sum;
}
}
return maxsum;
}
}
动态规划版本
class Solution {
public int maxSubArray(int[] nums) {
if (nums.length == 0 ) return 0;
int[] dp = new int[nums.length ];
dp[0] = nums[0];
int max = dp[0];
for (int i = 1; i < dp.length; i++) {
if (dp[i-1] > 0) {
dp[i] = dp[i-1] + nums[i];
}else {
dp[i] = nums[i];
}
max = Math.max(max, dp[i]);
}
return max;
}
}
剑指 Offer 43. 1~n整数中1出现的次数
- 输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。
例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。
示例 1:
输入:n = 12
输出:5
示例 2:
输入:n = 13
输出:6
class Solution {
public int countDigitOne(int n) {
return count(n);
}
public int count(int n){
if(n<=0){
return 0;
}
String s=String.valueOf(n);
int high=s.charAt(0)-'0';//层数
int pow=(int)Math.pow(10,s.length()-1);//
int last=n-high*pow;
if(high==1){
return last+1+count(pow-1)+count(last);
}
else{
return high*count(pow-1)+count(last)+pow;
}
}
}
剑指 Offer 44. 数字序列中某一位的数字
- 数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19位是4,等等。
请写一个函数,求任意第n位对应的数字。
示例 1:
输入:n = 3
输出:3
示例 2:
输入:n = 11
输出:0
class Solution {
public int findNthDigit(int n) {
if(n<0){
return -1;
}
if(n<=9){
return n;
}
int digt=1;
while(n>0.9*Math.pow(10,digt)*digt){
//获得几位数,以及获得在基准值上的偏移量
n-=0.9*Math.pow(10,digt)*digt;
digt++;
}
//获得基准值,偏移量除以位数。获得取到哪个数
int begin=(int)Math.pow(10,digt-1)+(n-1)/digt;
String s=String.valueOf(begin);
//偏移量取余,获得第几个字符
int i=(n-1)%digt;
return s.charAt(i)-'0';
}
}
剑指 Offer 45. 把数组排成最小的数
- 输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
示例 1:
输入: [10,2]
输出: "102"
示例 2:
输入: [3,30,34,5,9]
输出: "3033459"
注意大数问题,用字符串保存。自己构建一个比较器,来对比两个字符的拼接谁大。
class Solution {
public String minNumber(int[] nums) {
List list=new ArrayList<>();
for (int num:nums
) {
list.add(String.valueOf(num));
}
list.sort((s1,s2)->(s1+s2).compareTo(s2+s1));
StringBuilder builder=new StringBuilder();
for (String s:list
) {
builder.append(s);
}
return builder.toString();
}
}
题解处的stream流 写法。搬运一下 测试了一下,上一种耗时9ms,这种耗时18ms。作为知识储备吧。
class Solution {
public String minNumber(int[] nums) {
return Arrays.stream(nums)
.boxed()
.map(String::valueOf)
.sorted((s1,s2)->(s1+s2).compareTo(s2+s1))
.collect(Collectors.joining());
}
}
剑指 Offer 46. 把数字翻译成字符串
- 给定一个数字,我们按照如下规则把它翻译为字符串:
0 翻译成 “a” ,
1 翻译成 “b”,……,
11 翻译成 “l”,……,
25 翻译成 “z”。
一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
示例 1:
输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"
与青蛙跳台阶问题类似,动态规划解决,多出一步去掉一个无法翻译的情况就行。
class Solution {
public int translateNum(int num) {
if(num<0){
return 0;
}
String s=String.valueOf(num);
int a=1;
int b=1;
for(int i=2;i<=s.length();i++){
String tmp=s.substring(i-2,i);
int c = tmp.compareTo("10") >= 0 && tmp.compareTo("25") <= 0 ? a + b : a;
b=a;
a=c;
}
return a;
}
}
剑指 Offer 47. 礼物的最大价值
- 在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。
你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
示例 1:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 12
dp动态规划,grid[i][j]=max(grid[i-1][j],grid[i][j-1])+grid[i][j]),同时为了优化效率,率先初始化第一行和第一列
class Solution {
public int maxValue(int[][] grid) {
if(grid.length==0){
return 0;
}
int m=grid.length;
int n=grid[0].length;
for(int j=1;j
剑指 Offer 48. 最长不含重复字符的子字符串
- 请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
动态规划
class Solution {
public int lengthOfLongestSubstring(String s) {
if(s.length()==0){
return 0;
}
Map str=new HashMap<>();
int res=0;
int tmp=0;
for(int i=0;i
剑指 Offer 49. 丑数
- 我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。
示例:
输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
说明:
1 是丑数。
n 不超过1690。
动态规划 找到一个丑数的2倍,3倍或者5倍的最小值大于当前最大丑数,就是下一个丑数。
class Solution {
public int nthUglyNumber(int n) {
if(n==0){
return 0;
}
int[] x=new int[n];
int next=1;
x[0]=1;
int x2=0;
int x3=0;
int x5=0;
while(next
剑指 Offer 50. 第一个只出现一次的字符
在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。
s = "abaccdeff"
返回 "b"
s = ""
返回 " "
这是我率先想到的思路,用哈希表存储,有重复字符串则次数加一
class Solution {
public char firstUniqChar(String s) {
if(s.equals("")
){
return ' ';
}
Map str=new HashMap<>();
char[] x=s.toCharArray();
for (char p:x) {
if(str.get(p)!=null){
str.put(p,str.get(p)+1);
}
else{
str.put(p,1);
}
}
for (char key:x) {
if(str.get(key)==1){
return key;
}
}
return ' ';
}
}
题解区大佬做法,用数组代替哈希表,在确定容量的情况下更加高速,耗时4ms,上一种36ms
class Solution {
public char firstUniqChar(String s) {
int[] count = new int[256];
char[] chars = s.toCharArray();
for(char c : chars)
count[c]++;
for(char c : chars){
if(count[c] == 1)
return c;
}
return ' ';
}
}
作者:ustcyyw
链接:https://leetcode-cn.com/problems/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-lcof/solution/mian-shi-ti-50java-shi-yong-shu-zu-dai-ti-ha-xi-bi/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
剑指 Offer 51. 数组中的逆序对
- 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5
归并排序,在合并时计算逆序对的数量。
class Solution {
public int reversePairs(int[] nums) {
if(nums.length<2){
return 0;
}
int[] copy=new int[nums.length];
int[] tmp=new int[nums.length];
int count;
for (int i = 0; i
剑指 Offer 52. 两个链表的第一个公共节点
-
输入两个链表,找出它们的第一个公共节点。
如下面的两个链表:
在节点 c1 开始相交。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。
- 如果两个链表没有交点,返回 null.
- 在返回结果后,两个链表仍须保持原有的结构。
- 可假定整个链表结构中没有循环。
- 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
双指针移动,长链表先走几步直到剩余长度与短链表一致。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int xlength=getLength(headA);
int ylength=getLength(headB);
ListNode longNode=headA;
ListNode shortNode=headB;
int length=xlength-ylength;
if(xlength