T4:k 镜像数字的和
- 暴力的代码(不断迭代生成十进制回文数值)
- 利用回文数值的递归形式
- 两边加入相同的数,中间从小到大插入n - 2位的数,其中n是当前欲生成回文数的位数
class Solution {
public boolean isparlid(String s)
{
int low = 0;
int high = s.length() - 1;
while(low<=high)
{
if(s.charAt(low) == s.charAt(high))
{
low++;
high--;
}
else return false;
}
return true;
}
/**
* 将十进制数转换为k进制数
* @param n
* @return
*/
public String DtoK(long n,int K)
{
StringBuilder s = new StringBuilder();
do
{
s.insert(0,n%K);
n/=K;
}while(n!=0);
return s.toString();
}
public long kMirror(int k, int n) {
//从小到大生成回文数
Map<Integer,List<String>> temp = new HashMap<>();
//一位数
long ans = 0;
int count = 0;
temp.put(1,new ArrayList<>());
temp.get(1).add("0");
for(int i = 1;i<=9;i++)
{
temp.get(1).add(Character.valueOf((char)(i + '0')).toString());
if(isparlid(DtoK((long)i,k))) {
ans += i;
count++;
System.out.println(i);
if(count == n)
return ans;
}
}
//两位数
temp.put(2,new ArrayList<>());
temp.get(2).add("00");
for(int i = 11;i<=99;i+=11)
{
temp.get(2).add(Integer.valueOf(i).toString());
if(isparlid(DtoK(i,k)))
{
ans+=i;
count++;
System.out.println(i);
if(count == n)
return ans;
}
}
//三位数开始递归利用前面的构造
for(int i = 3;;i++)
{
temp.put(i,new ArrayList<>());
for(char j = '0';j<='9';j++)
{
for(String a : temp.get(i - 2))
{
String b = j + a + j;
temp.get(i).add(b);
if(j!='0' && isparlid(DtoK(Long.parseLong(b),k)))
{
System.out.println(b);
ans+=Long.parseLong(b);
count++;
if(count == n)
return ans;
}
}
}
}
}
// public static void main(String[] args)
// {
// System.out.println(new Solution().DtoK(6958596,7));
// new Solution().kMirror(7,17);
// }
}
优化1(二分搜索)
优化2(打表 不多说)
class Solution {
private:
static constexpr long long ans[][30] = {
{1, 3, 5, 7, 9, 33, 99, 313, 585, 717, 7447, 9009, 15351, 32223, 39993, 53235, 53835, 73737, 585585, 1758571, 1934391, 1979791, 3129213, 5071705, 5259525, 5841485, 13500531, 719848917, 910373019, 939474939},
{1, 2, 4, 8, 121, 151, 212, 242, 484, 656, 757, 29092, 48884, 74647, 75457, 76267, 92929, 93739, 848848, 1521251, 2985892, 4022204, 4219124, 4251524, 4287824, 5737375, 7875787, 7949497, 27711772, 83155138},
{1, 2, 3, 5, 55, 373, 393, 666, 787, 939, 7997, 53235, 55255, 55655, 57675, 506605, 1801081, 2215122, 3826283, 3866683, 5051505, 5226225, 5259525, 5297925, 5614165, 5679765, 53822835, 623010326, 954656459, 51717171715},
{1, 2, 3, 4, 6, 88, 252, 282, 626, 676, 1221, 15751, 18881, 10088001, 10400401, 27711772, 30322303, 47633674, 65977956, 808656808, 831333138, 831868138, 836131638, 836181638, 2512882152, 2596886952, 2893553982, 6761551676, 12114741121, 12185058121},
{1, 2, 3, 4, 5, 7, 55, 111, 141, 191, 343, 434, 777, 868, 1441, 7667, 7777, 22022, 39893, 74647, 168861, 808808, 909909, 1867681, 3097903, 4232324, 4265624, 4298924, 4516154, 4565654},
{1, 2, 3, 4, 5, 6, 8, 121, 171, 242, 292, 16561, 65656, 2137312, 4602064, 6597956, 6958596, 9470749, 61255216, 230474032, 466828664, 485494584, 638828836, 657494756, 858474858, 25699499652, 40130703104, 45862226854, 61454945416, 64454545446},
{1, 2, 3, 4, 5, 6, 7, 9, 121, 292, 333, 373, 414, 585, 3663, 8778, 13131, 13331, 26462, 26662, 30103, 30303, 207702, 628826, 660066, 1496941, 1935391, 1970791, 4198914, 55366355},
{1, 2, 3, 4, 5, 6, 7, 8, 191, 282, 373, 464, 555, 646, 656, 6886, 25752, 27472, 42324, 50605, 626626, 1540451, 1713171, 1721271, 1828281, 1877781, 1885881, 2401042, 2434342, 2442442}
};
public:
long long kMirror(int k, int n) {
return accumulate(ans[k - 2], ans[k - 2] + n, 0LL);
}
};
二分查找类型总结
总结的动机是本次竞赛T3花费了很长时间,表明了对二分查找不熟悉。现在总结下二分查找的几种类型及其类型。
- 可以证明 mid = (right + left)/2和mid = left + (right - left)/2结果是相同的,那么采用哪一种?
- 采用后者,防止了数值溢出!
在递增序列中找到一个数
int binarySearch(int[] nums, int target) {
int left = 0;
int right = nums.length - 1; // 注意
while(left <= right) {
int mid = left + (right - left) / 2;
if(nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1; // 注意
else if (nums[mid] > target)
right = mid - 1; // 注意
}
return -1;
}
- 使用小于等于的原因:当while测试条件为left<=right时,搜索区间为[left,right];当while测试条件为left<right时,搜索区间为[left,right)(不包含right下标)