一、两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入: nums = [2,7,11,15], target = 9
输出: [0,1]
解释: 因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入: nums = [3,2,4], target = 6
输出: [1,2]
示例 3:
输入: nums = [3,3], target = 6
输出: [0,1]
提示:
2 <= nums.length <= 104-109 <= nums[i] <= 109-109 <= target <= 109- 只会存在一个有效答案
二、思路解法
1.第一种
public static int[] TwoSum(int[] nums, int target)
{
int[] intArr = new int[2];
for (int i = 0; i < nums.Length; i++)
{
for (int j = 0; j < nums.Length; j++)
{
if (i == j) break;
if (nums[i] + nums[j] == target)
{
intArr[0] = j;
intArr[1] = i;
}
}
}
return intArr;
}
2.第二种:
public static int[] TwoSum(int[] nums, int target)
{
int[] intArr = new int[2];
for (int i = 0; i < nums.Length; i++)
{
for (int j = i+1; j < nums.Length; j++)
{
if (nums[i] + nums[j] == target)
{
intArr[0] = i;
intArr[1] = j;
}
}
}
return intArr;
}
3.第三种:
public static int[] TwoSum(int[] nums, int target)
{
int[] intArr = new int[2];
//创建一个哈希表
Hashtable ht = new Hashtable();
//将值存储在哈希表中
for (int i = 0; i < nums.Length; i++)
{
//将值以及值对应的索引存入到哈希表中
ht.Add(nums[i],i);
}
//再次循环遍历,
for (int i = 0; i < nums.Length; i++)
{
//计算差值
int diff = target- nums[i];
//判断差值是否在哈希表中
if(ht.ContainsKey(diff) && (int)ht[diff]!=i)
{
intArr[0] = (int)ht[diff];
intArr[1] = i;
}
}
return intArr;
}
}
第三种方式采用的是哈希表存储键(数组的值),值(数组的值对应的下标的值),哈希表是不允许键重复的,所以在针对于键不重复的是可以进行通过的,为此这里只提供这个思路。
测试代码:
static void Main(string[] args)
{
/*string s = "(){}[]";
IsValid(s);*/
int[] nums = { 3, 7, 11, 3 };
int[] result = TwoSum(nums, 6);
for(int i = 0; i < result.Length; i++)
{
if (i == result.Length - 1)
{
Console.WriteLine(result[i]);
}
else
{
Console.Write(result[i]+",");
}
}
}
三、哈希表复习
C#中的是一种数据结构,可以用于存储键值对,并提供快速的访问和搜索功能。在C#中,哈希表是通过Hashtable类实现的。
下面我们学习最基本的哈希表的使用
1.哈希表的创建
Hashtable hashtable = new Hashtable();
2.添加元素
hashtable.Add("key1", "value1");
hashtable.Add("key2", 22);
hashtable.Add("key3", "value3");
注意哈希表添加元素的时候,可以使用多种数据类型进行添加
3.获取元素
string value1 = (string)hashtable["key1"];
string value2 = (string)hashtable["key2"];
通过键访问对应的value值返回的是Object类型,后续需要强转成自己想要的类型
4.更新元素
hashtable["key3"] = "new value3";
5.删除元素
hashtable.Remove("key2");
6.遍历哈希表
foreach (DictionaryEntry entry in hashtable)
{
string key = (string)entry.Key;
string value = (string)entry.Value;
Console.WriteLine("Key: {0}, Value: {1}", key, value);
7.获取键的集合
ICollection keys = hashtable.Keys;
Console.WriteLine("哈希表中的键:");
foreach (string key in keys)
{
Console.WriteLine(key);
}
8.获取值的集合
// 获取值的集合
ICollection values = hashtable.Values;
Console.WriteLine("哈希表中的值:");
foreach (object value in values)
{
Console.WriteLine(value);
}
9.判断键和值是否存在哈希表中
bool containsKey = hashtable.ContainsKey("name");
Console.WriteLine("哈希表中是否包含键\"name\":{0}", containsKey);
// 判断哈希表中是否包含指定的值
bool containsValue = hashtable.ContainsValue("New York");
Console.WriteLine("哈希表中是否包含值\"New York\":{0}", containsValue);
四、哈希表与字典的区别
Dictionary<K,V>是泛型的,当K或V是值类型时,其速度远远超过Hashtable。
补充:C# 哈希表Hashtable与字典表Dictionary<K,V>的比较。
一、Hashtable 和 Dictionary <K, V> 类型
1):单线程程序中推荐使用 Dictionary, 有泛型优势, 且读取速度较快, 容量利用更充分.
2):多线程程序中推荐使用 Hashtable, 默认的 Hashtable 允许单线程写入, 多线程读取, 对 Hashtable 进一步调用 Synchronized()方法可以获得完全线程安全的类型. 而Dictionary 非线程安全, 必须人为使用 lock 语句进行保护, 效率大减.
3):Dictionary 有按插入顺序排列数据的特性 (注: 但当调用 Remove() 删除过节点后顺序被打乱), 因此在需要体现顺序的情境中使用 Dictionary 能获得一定方便.
在使用哈希表保存集合元素(一种键/值对)时,首先要根据键自动计算哈希代码,以确定该元素的保存位置,再把元素的值放入相应位置所指向的存储桶中。在查找时,再次通过键所对应的哈希代码到特定存储桶中搜索,这样将大大减少为查找一个元素进行比较的次数。
HashTable中的key/value均为object类型,由包含集合元素的存储桶组成。存储桶是 HashTable中各元素的虚拟子组,与大多数集合中进行的搜索和检索相比,存储桶可令搜索和检索更为便捷。每一存储桶都与一个哈希代码关联,该哈希代码是使用哈希函数生成的并基于该元素的键。HashTable的优点就在于其索引的方式,速度非常快。如果以任意类型键值访问其中元素会快于其他集合,特别是当数据量特别大的时候,效率差别尤其大。
HashTable的应用场合有:做对象缓存,树递归算法的替代,和各种需提升效率的场合。
1.2.字典:
找不到返回error
不拆箱,装箱所以比hashtable快
只有公共的静态成员都是线程安全的。
Dictionary 是一个泛型类型,这意味着我们可以使用它与任何数据类型。
哈希表:
找不到返回null
需要拆箱装箱所以比dictionary慢
所有成员都是线程安全的
不是一个泛型类型
主要的区别是,哈希表使用多线程做,可以多线程读取,字典单线程读取
五、伪代码
为什么要使用伪代码
好处:
1.辅助开发,可以站在一较高层次上编写代码,而不陷入语法细节, 代替流程图。
2.可以直接将伪代码变成注释,省去编写注释的时间
3.代码变更时,修改伪代码,比修改几十行代码来的容易
要求:
- 避免使用目标语言的语法元素。
- 在意图层面上编写伪代码 。更加接近解决问题的核心,不落入语法细节。
- 在一个足够低的层次上编写伪代码 。便于伪代码转化成代码。
什么时候需要伪代码:
当编写代码困难时,可以 降低代码有复杂度,降低代码实现难度。不随意的编写伪代码,保证伪代码足够的简洁,方便审查代码漏洞。
力求代码足够的接近底层。使伪代码能够快速转化成代码。