一、Markdown基本语法
1. 标题
使用#表示标题(需在行首,其与标题文字间加空格)
#数目越多,标题字号越小;
最高支持六级标题。
2. 字体特效
使用 * 表示特效(目标文字前后均需加 * ,且 * 与目标文字间无空格)
目标文字前后均加 * ,显示斜体;
目标文字前后均加 ** ,显示加粗;
目标文字前后均加 *** ,显示 斜体加粗。
3. 列表
(1)无序
使用-或 * 表示无序列表(需在行首,且其后需加空格)
- -或 * 后文字前显示序点。
(2)有序
使用 阿拉伯数字 加 . 表示有序列表(需在行首,且其后需加空格)
- 所见即所得。
4. 引用
使用 > 表示引用(需在行首)
后的文字出现在引用框内。
5. 插入
(1)超链接
使用 []与()连用 表示超链接([]里是链接文字,()内是链接地址)
(1)图片
使用 !加[]与()连用 表示图标([]里是图片提示文字,()内是图片地址)
6. 代码
使用 ' 表示代码(目标代码前后均需加 ')
代码内容
二、数组与字符串
1. 寻找数组的中心索引
题目要求
- 数组nums的长度范围为 [0, 10000],且任何一个nums[i]将会是一个范围在 [-1000, 1000]的整数
- 返回数组 “中心下标” - 左侧所有元素相加的和等于右侧所有元素相加的和的元素的下标
- 不存在中心下标,返回 -1
- 有多个中心下标,返回最靠近左边的那一个
- 中心下标可能出现在数组的两端
示例
示例 1:
输入:nums = [1, 7, 3, 6, 5, 6]
输出:3
解释:
中心下标是 3 。
左侧数之和 (1 + 7 + 3 = 11),
右侧数之和 (5 + 6 = 11) ,二者相等。
示例 2:
输入:nums = [1, 2, 3]
输出:-1
解释:
数组中不存在满足此条件的中心下标。
示例 3:
输入:nums = [2, 1, -1]
输出:0
解释:
中心下标是 0 。
下标 0 左侧不存在元素,视作和为 0 ;
右侧数之和为 1 + (-1) = 0 ,二者相等。
思路
-
“左侧所有元素相加的和等于右侧所有元素相加的和”,由于中心下标暂未知,所以其左侧与右侧的元素和都无法确定,而数组总和是确定的,有:左侧和 == 右侧和 == 1/2 * (数组总和 - 当前元素);
-
“多中心下标时,返回最左的那一个”,可确定考虑方向是从最左端开始;
-
因"整型数组nums",若数组总和 - 当前元素为奇数,则更新左侧和后,可以直接开始下一次循环;
-
考虑到乘除比加减运算开销更大,故最终判定中心下标的条件是:(数组总和 - 当前元素) - 左侧和 == 左侧和。
具体实现
- 第一次循环:遍历数组,求数组总和。
- 第二次循环:顺序求和,当(数组总和 - 当前元素) - 左侧和 == 左侧和时,返回当前元素下标,结束循环。
题解代码
public class Solution {
public int PivotIndex(int[] nums) {
if (nums.Length == 0)
{
return -1;
}
int totalSum = 0, leftSum = 0, i;
foreach (int n in nums)
{
totalSum += n;
}
for (i = 0; i < nums.Length; i++)
{
if ((totalSum - nums[i]) % 2 != 0)
{
leftSum += nums[i];
continue;
}
else if (totalSum - nums[i] - leftSum == leftSum)
{
return i;
}
leftSum += nums[i];
}
return -1;
}
}
效率分析
运行时间min - 116 ms
public class Solution {
public int PivotIndex(int[] nums) {
int sum = 0, flag = 0, end = 0;
for (int i = 0; i < nums.Length; i++)
{
sum += nums[i];
}
if (sum - nums[0] == 0)
{
return 0;
}
for (int j = 0; j < nums.Length; j++)
{
flag += nums[j];
if (j != 0)
{
end = flag - nums[j];
}
while (end == sum - flag)
{
return j;
}
}
return -1;
}
}
内存消耗min - 31048 kb
public class Solution {
public int PivotIndex(int[] nums)
{
int total = nums.Sum();
int sum = 0;
for (int i = 0; i < nums.Length; i++) {
if (sum * 2 + nums[i] == total) {
return i;
}
sum += nums[i];
}
return -1;
}
}
反思
- 一开始忽略了C#的整型除法,但也由此想到了如果(数组总和 - 当前元素)为奇数,那么当前下标非中心下标。
- 通过对比别人的代码,发现自己漏掉了数组长为0的特殊情况。
- 调整某些语句的先后顺序,可以改善时间效率。
- Sum()函数求和。
2. 搜索插入位置
题目要求
-
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。
-
如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
-
假设数组中无重复元素。
示例
示例 1:
输入: [1,3,5,6], 5
输出: 2
示例 2:
输入: [1,3,5,6], 2
输出: 1
示例 3:
输入: [1,3,5,6], 7
输出: 4
示例 4:
输入: [1,3,5,6], 0
输出: 0
思路
-
由上一题的sum()函数求和想到先利用函数按值查找目标值是否存在于数组中;
-
若不存在,则由“排序数组”可想到利用二分法找到插入位置。
具体实现
通过查阅资料,找到了C#中按值返回数组/字符串元素索引的函数,System下的Array.IndexOf(Array, Object)。
题解代码
public class Solution {
public int SearchInsert(int[] nums, int target) {
if (Array.IndexOf(nums, target) != -1)
{
return Array.IndexOf(nums, target);
}
int start = 0, middle, end = nums.Length-1;
if (target > nums[end])
{
return end+1;
}
while (target > nums[start])
{
middle = (start + end) / 2;
if(target > nums[middle])
{
start = middle + 1;
continue;
}
else
{
end = middle;
continue;
}
start++;
}
return start;
}
}
效率分析
运行时间min - 84 ms
public class Solution {
public int SearchInsert(int[] nums, int target)
{
for(int i=0;i<nums.Length;i++)
{
if(nums[i]>=target)
return i;
}
return nums.Length;
}
}
内存消耗min - 24764 kb
public class Solution {
public int SearchInsert(int[] nums, int target)
{
int left = 0, right = nums.Length - 1, mid;
while (left <= right)
{
mid = left + ((right - left) >> 1);
//右移运算符>>,运算结果正好能对应一个整数的二分之一值,这就正好能代替数学上的除2运算,但是比除2运算要快。
//(left-right)>>1相当于(left-right)/2,此处防止数据过大溢出。
if (nums[mid] >= target)
{
right = mid - 1;
}
else
{
left = mid + 1;
}
}
return left;
}
}
反思
- 学会类型的归整,比如插入位置在原数组末的情况不必单独列出。
- 对于二分法中的“+1”、“-1”还有点模糊。
- 运行时长min的解法竟是直接遍历,一定是测试的长数组还不够多。
- Microsoft官方的C#文档很方便。
- 右移运算符 & Array.IndexOf()函数
3. 最长公共前缀
题目要求
-
编写一个函数来查找字符串数组中的最长公共前缀。
-
如果不存在公共前缀,返回空字符串
""。 -
0 <= strs.length <= 200 -
0 <= strs[i].length <= 200 -
strs[i]仅由小写英文字母组成
示例
示例 1:
输入:strs = ["flower","flow","flight"]
输出:"fl"
示例 2:
输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。
思路
- 若字符串组为空, 则返回""。
- 最长公共前缀的长度 <= min{字符串组中元素长度}, 所以先对字符串组进行按长度升序排序, 并以第一个元素(长度最短)为参照, 与字符串组元素逐位比较。
- 出现不等
- 若是第一个字符, 说明无公共前缀,返回"";
- 否则, 返回第一个元素的子串。
- 未出现不等
- 返回第一个元素。
- 出现不等
具体实现
经查询找到了System.Linq下的OrderBy方法对数据进行排序(长度/字母表顺序)。
题解代码
public class Solution
{
public string LongestCommonPrefix(string[] strs)
{
if (strs.Length == 0)
{
return "";
}
strs = strs.OrderBy(r => r.Length).ToArray<string>();
for (int i = 0; i < strs[0].Length; i++)
{
for (int j = 0; j < strs.Length; j++)
{
if (strs[0][i] != strs[j][i])
{
if (i == 0)
{
return "";
}
else
{
return strs[0].Substring(0, i);
}
}
}
}
return strs[0];
}
}
效率分析
运行时间min-96 ms
public class Solution
{
public string LongestCommonPrefix(string[] strs)
{
var length = strs.Length;
var result = "";
if (length <= 0)
{
return result;
}
var first = strs[0];
var firstLength = first.Length;
for (int i = 0; i < firstLength; i++)
{
var trueCount = 0;
foreach (var val in strs)
{
if (i >= val.Length) break;
if (val[i] == first[i])
{
trueCount++;
}
}
if (trueCount == length)
{
result += first[i];
}
else
{
break;
}
}
return result;
}
}
内存消耗min-24820 kb
public class Solution
{
public string LongestCommonPrefix(string[] strs)
{
var result = "";
if (strs.Length == 0) return result;
var index = 0;
while (index < strs[0].Length)
{
for (var i = 1; i < strs.Length; i++)
{
if (index >= strs[i].Length || strs[i][index] != strs[0][index])
return result;
}
result += strs[0][index];
index++;
}
return result;
}
}
反思
-
运行时间和内存最小的解决方案都没有排序,平心而论,如果我没有排序,第一遍运行时肯定会因为没有注意元素下标越界而报错。
-
OrderBy & Substring