《剑指offer》算法题第一天

按照个人计划,从今天开始做《剑指offer》上面的算法题,练习平台为牛客网,上面对每道题都有充分的测试实例,感觉还是很不错的。今天下午做了四道题,分别为:

1. 二叉树的深度(书55题)

二叉树的深度

判断平衡二叉树

2. 数组中数字出现的次数(书56题)

  数组中只出现一次的两个数字

3. 和为S的数字(书57题)

  和为S的连续正数序列

  和为S的两个数字

4. 翻转字符串(书58题)

  左旋转字符串

  翻转单词顺序列

二叉树类型的问题在leetcode上多次遇到,剑指上的题也比较简单,这边就不再说明,只在最后贴出代码,需要注意的是判断平衡二叉树如何使用一次遍历来判断(利用后序遍历,从叶节点往上判断)。

和为S的数字利用的是Two Pointers的思想,也算比较容易,所以今天的重点是第2,4题。

 

 

2. 数组中数字出现的次数

题目描述:一个整型数组里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

本题采用位运算,与leetcode上137. Single Number II类似,且在Discuss中有大神贴出了解法和数学解释,感兴趣的同学可以了解一下。与leetcode上不同的是,本题有两个数字只出现一次,因此较为麻烦。

复制代码
思路:

如果能把原数组分为两个只有一个数字出现的子数组,就能够用异或运算得出这两个数。

从头到尾异或数组中的每个数字,最终得到两个只出现一次的数字的异或结果。

由于这两个数字不一样,异或的结果肯定不为0,也就是说这个结果数字的二进制表示中至少有一位为1。

在结果数字中找到第一个为1的位的位置,记为第n位,以第n位是不是1为标准把原数组中的数字分成两个子数组,第一个子数组中每个数字的第n位都是1,而第二个子数组中每个数字的第n位都是0。这样,就把原数组分为了两个子数组,在每个子数组中只有一个数出现一次,其他数字都出现了两次。
复制代码

实现代码:

复制代码
 1 //num1,num2分别为长度为1的数组。传出参数
 2 //将num1[0],num2[0]设置为返回结果
 3 public class Solution {
 4     public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
 5         int t = 0; //第一轮异或的结果
 6         for(int n:array){
 7             t ^= n;
 8         }
 9         int firstOne = FindFirstOne(t);//找到第一位1的位置
10         num1[0] = 0;
11         num2[0] = 0;
12         for(int n:array){
13             if(IsBit1(n,firstOne)){//根据第n位是否为1将数组分开
14                 num1[0] ^= n;
15             }else{
16                 num2[0] ^= n;
17             }
18         }
19     }
20     
21     public int FindFirstOne(int t){
22         int first = 0;
23         while((t & 1) == 0 && first < 32){//int型为32位
24             t = t>>1;
25             first++;
26         }
27         return first;
28     }
29     
30     public boolean IsBit1(int num,int indexBit){
31         num = num >> indexBit;
32         return (num & 1) == 1;
33     }
34 }
复制代码

 

4. 翻转字符串

复制代码
题目描述:

翻转单词顺序:

输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。

为简单起见,标点符号和普通字母一样处理。如“I am a student.”,则输出为"student. a am I"。

左旋转字符串:

把字符串前面的若干个字符转移到字符串的尾部。

如输入"abcdefg"和数字2,则输出“cdefgab”。
复制代码

这题考察的如何灵活的运用字符串翻转来处理新的问题,下面给出字符串翻转的实现代码,代码中,字符串首先被转化为字符数组再进行操作。

复制代码
 1 public void ReverseString(char[] array,int start,int end){
 2     if(start >= end)
 3         return;
 4     while(start < end){
 5         char tmp = array[start];
 6         array[start] = array[end];
 7         array[end] = tmp;
 8         start++;
 9         end--;
10     }
11 }
复制代码

思路如下:

复制代码
翻转单词顺序:

首先将句子中的所有字符翻转,如"I am a student."翻转得到".tneduts a ma I"

再将句子内的单词翻转回来得到"student. a am I"



左旋转字符串:
以"abcdefg"为例,把字符串根据n分为两部分
先对每一部分分别翻转,得到"bagfedc"

然后再对整个字符串进行翻转,得到"cdefgab"
复制代码

代码如下:

翻转单词顺序:

复制代码
public String ReverseSentence(String str) {
        char[] array = str.toCharArray();
        ReverseString(array,0,array.length-1);
        int s = 0;
        for(int end = 0; end < array.length; end++){
            if(array[end] == ' '){
                ReverseString(array,s,end-1);
                s = end+1;
            }
        }
        ReverseString(array,s,array.length-1);
        return String.valueOf(array);
    }
复制代码

左旋转字符串:

复制代码
public String LeftRotateString(String str,int n) {
        int len = str.length();
        if(len <= 1 || n%len == 0) return str;
        n %= len;
        char[] array = str.toCharArray();
        ReverseString(array,0,n-1);
        ReverseString(array,n,len-1);
        ReverseString(array,0,len-1);
        return String.valueOf(array);
    }
复制代码

 

 

 

 

最后贴上第1和第3题的代码:

二叉树:

复制代码
//二叉树的深度
public class Solution {
    public int TreeDepth(TreeNode root) {
        if(root == null)
            return 0;
        int left = TreeDepth(root.left);
        int right = TreeDepth(root.right);
        return Math.max(left,right)+1;
    }
}


//判断平衡二叉树
public class Solution {
    public boolean IsBalanced_Solution(TreeNode root) {
        if(root == null)
            return true;
        return maxDepth(root) != -1;
    }
    
    public int maxDepth(TreeNode node){
        if(node == null)
            return 0;
        int left = maxDepth(node.left);
        int right = maxDepth(node.right);
        if(left == -1 || right == -1 || Math.abs(left-right) > 1){
            return -1;
        }
        return Math.max(left,right)+1;
    }
}
复制代码

 

 

和为S的数字:

复制代码
//和为S的两个数字
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
        ArrayList<Integer> res = new ArrayList();
        if(array.length == 0) return res;
        int head = 0, tail = array.length-1;
        while(head < tail){
            int p = array[head];
            int q = array[tail];
            if(p+q == sum){
                res.add(p);
                res.add(q);
                break;
            }else if(p+q > sum){
                tail --;
            }else{
                head ++;
            }
        }
        return res;
    }
}


//和为S的连续正数序列
import java.util.ArrayList;
public class Solution {
    public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
        int small = 1, big = 2, mid = (sum+1)/2;
        ArrayList<ArrayList<Integer>> res = new ArrayList();
        ArrayList<Integer> tmp = new ArrayList();
        tmp.add(small);
        tmp.add(big);
        int total = small+big;
        while(small < mid){
            if(total == sum){
                res.add(new ArrayList(tmp));
            }
            if(total > sum){
                total -= small;
                small++;
                tmp.remove(0);
            }else{
                big++;
                total += big;
                tmp.add(big);
            }
        }
        return res;
    }
}
复制代码

 

posted @   wezheng  阅读(226)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
点击右上角即可分享
微信分享提示