剑指offer

offer 03 数组中的重复数字

题目描述:
找出数组中重复的数字。

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

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

我的思路:
一.用字典。
存在的问题:①一开始字典并未赋值,所以不能用if(dic[nums[i]]!=null),此时会报错说key值不存在,只有用ADD方法添加了key和value后才可以判断。
修改:可以使用dic.ContainsKay();方法来判断Key是否存在!
代码:

public class Solution {
   
    public int FindRepeatNumber(int[] nums) {
   
Dictionary<int,int> dic=new Dictionary<int,int>();
for(int i=0;i<nums.Length;i++)
{
   
if(dic.ContainsKey(nums[i])) return nums[i];
else {
    dic.Add(nums[i],i);  }

}

return -1;
    }
}
执行用时:176 ms
内存消耗:38.9 MB
很慢!

思路二:用一个长度为n的数组,value[nums[i]]=nums[i];如果插入时发现已有值,则返回。
针对数组初始化是都为0的情况,设置一个int值存储0出现的次数。
代码:

public class Solution {
   
    public int FindRepeatNumber(int[] nums) {
   
int [] value=new int [nums.Length];
int numberofzero=0;
for(int i=0;i<nums.Length;i++)
{
   
if(nums[i]==0) numberofzero++;
if(numberofzero>1) return 0;
if((nums[i]!=0)&&value[nums[i]]==nums[i]) return nums[i];
else value[nums[i]]=nums[i];

}
return -1;
    }
}
执行用时:
172 ms, 在所有 C# 提交中击败了44.69%的用户
内存消耗:
36 MB, 在所有 C# 提交中击败了100.00%的用户

思路三:对于思路二的改进,用value来存储次数即可,就可以避免了0的特殊情况
BUG:对于重复的判断语句出现问题,应该是》=1,而不是》=2
方法改进:用一个int类型来存储当前查询的序号,会快上一点。int curr=nums【i】;
代码:

public class Solution {
   
    public int FindRepeatNumber(int[] nums) {
   
int [] value=new int [nums.Length];

for(int i=0;i<nums.Length;i++)
{
   
if(value[nums[i]]>=1) return nums[i];
else value[nums[i]]++;

}
return -1;
    }
}
执行用时:
172 ms, 在所有 C# 提交中击败了44.69%的用户
内存消耗:
36 MB, 在所有 C# 提交中击败了100.00%的用户

解题方法一:原地置换
思路:将整个数组从0开始排序,如果有重复数字,则返回
难点:①如何通过一次循环完成排序?②重复数字的判断条件
代码:

public class Solution {
   
    public int FindRepeatNumber(int[] nums) {
   
int temp;
for(int i=0;i<nums.Length;i++)
{
   
while(nums[i]!=i)//如果用了if,不能通过一次循环来置换
{
   
if(nums[i]==nums[nums[i]]) return nums[i];//通过判断数字是否相同来判断是否重复!
temp=nums[i];
nums[i]=nums[temp];
nums[temp]=temp;

}

}
return -1;
    }
}
执行用时:
160 ms, 在所有 C# 提交中击败了79.38%的用户
内存消耗:
35.3 MB, 在所有 C# 提交中击败了100.00%的用户

offer 04 二维数组的查找

题目描述:
在一个 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。

我的思路:
首先要缩小范围,先求得target可能存在的最大行号,再求得最小行号。再求最小列,最后再求最大列。
注意先判断两种特殊情况:target小于最小值和大于最大值
代码:

public class Solution {
   
    public bool FindNumberIn2DArray(int[][] matrix, int target) {
   
        if(matrix == null || matrix.Length == 0 || matrix[0].Length == 0) return false;
int row=matrix.GetLength(0);
int col=matrix[0].Length;
if(matrix[0][0]>target||matrix[row-1][col-1]<target) return false;//判断特殊情况
int minrow,maxrow,mincol,maxcol;
int left=0,right=row-1,mid;
while(left<=right)//求最大行
{
   
mid=(left+right)/2;
if(matrix[mid][0]==target) return true;
else if(matrix[mid][0]<target) left=mid+1;
else right=mid-1;
}
maxrow=right; left=0;right=maxrow;
while(left<right)//求最小行
{
   

mid=(left+right)/2;
if(matrix[mid][col-1]==target) return true;
else if(matrix[mid][col-1]<target) left=mid+1;
else right=mid;

}
minrow=right; left=0;right=col-1;
while(left<right)//求最小列
{
   
mid=(left+right)/2;
if(matrix[maxrow][mid]==target) return true;
else if(matrix[maxrow][mid]<target) left=mid+1;
else right=mid;

}
mincol=right;left=mincol;right=col-1;
while(left<=right)//求最大列
{
   
mid=(left+right)/2;
if(matrix[0][mid]==target) return true;
else if(matrix[0][mid]<target) left=mid+1;
else right=mid-1;

}
maxcol=right;

for(int i=minrow;i<=maxrow;i++)//查找
for(int j=mincol;j<=maxcol;j++)
if(matrix[i][j]==target) return true;

return false;
    }
}
执行用时:
148 ms, 在所有 C# 提交中击败了60.39%的用户
内存消耗:
31.2 MB, 在所有 C# 提交中击败了100.00%的用户

offer 05替换空格

题目描述:
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
示例 1:
输入:s = “We are happy.”
输出:“We%20are%20happy.”

我的思路:将字符串逐个扫描,遇到空格则用%20替代
代码:

public class Solution {
   
    public string ReplaceSpace(string s) {
   
string result="";
for(int i=0;i<s.Length;i++)
{
   
if(s[i]==' ') result+="%20";
else result+=s[i];

}
return result;
    }
}
执行用时:
124 ms, 在所有 C# 提交中击败了9.77%的用户
内存消耗:
25 MB, 在所有 C# 提交中击败了100.00%的用户

offer 06 从尾到头打印链表

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

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

我的解题思路: 用栈
代码:

public class Solution {
   
    public int[] ReversePrint(ListNode head) {
          
Stack<int> stack=new Stack<int>();
while(head!=null)
{
   
stack.Push(head.val);
head=head.next;
}
int [] num=new int[stack.Count]; int i=0;
while(stack.Count!=0)
num[i++]=stack.Pop();

return num;
    }
}
执行用时:
276 ms, 在所有 C# 提交中击败了89.35%的用户
内存消耗:
31.6 MB, 在所有 C# 提交中击败了100.00%的用户

offer 07 重建二叉树

题目描述:
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:

3

/
9 20
/
15 7

我的解题思路:
首先,把根节点,以及根结点的DLR,LDR数组传进去。找到根节点的左孩子和右孩子,并且赋予给根结点,然后不断对左孩子和右孩子进行递归。
代码:

public class Solution {
   
    public TreeNode BuildTree(int[] preorder, int[] inorder) {
   
        if(preorder.Length==0||inorder.Length==0) return null;
TreeNode root =new TreeNode(preorder[0]);
Process(root,0,preorder.Length-1,0,inorder.Length-1,preorder,inorder);//首先要把root传进去
return root;
    }
   void Process(TreeNode root,int preleft,int preright,int inleft,int inright,int [] preorder,int[] inorder)
   {
   
if(root.val==int.MaxValue||preleft==preright||inleft==inright) return ;
//判断不需要处理的情况
int 

你可能感兴趣的:(数据结构,c#)